1. 程式人生 > >CF1097D Makoto and a Blackboard 積性函式、概率期望、DP

CF1097D Makoto and a Blackboard 積性函式、概率期望、DP

傳送門


比賽秒寫完ABC結果不會D……最後C還fst了qwq

首先可以想到一個約數個數\(^2\)乘上\(K\)的暴力DP,但是顯然會被卡

\(10^{15}\)範圍內因數最多的數是\(978217616376000=2^6 \times 3^4 \times 5^3 \times 7^2 \times 11 \times 13 \times 17 \times 19 \times 23 \times 29\),它有\(26880\)個因數

但是不難發現:在我們的答案中參與計算的只有約數個數和函式和約數和函式。它們都是傳統的積性函式。這給我們一些啟示:可以考慮分解質因數然後DP。

考慮對一個數\(x=p^k\)

進行\(DP\),設\(f_{i,j}\)表示初始數字為\(p^j\)、做\(i\)輪操作的期望值,轉移為\(f_{i,j} = \frac{\sum\limits_{k=0} ^ j f_{i-1,k}}{j+1}\),使用字首和優化轉移。最後將所有質因數得到的答案乘起來就是最後的答案。

#include<bits/stdc++.h>
#define int long long
//This code is written by Itst
using namespace std;

inline int read(){
    int a = 0;
    char c = getchar();
    bool f = 0;
    while(!isdigit(c) && c != EOF){
        if(c == '-')
            f = 1;
        c = getchar();
    }
    if(c == EOF)
        exit(0);
    while(isdigit(c)){
        a = a * 10 + c - 48;
        c = getchar();
    }
    return f ? -a : a;
}

const int MOD = 1e9 + 7;
int dp[50][10010] , inv[52];

inline int poww(int a , int b){
    int times = 1;
    while(b){
        if(b & 1)
            times = times * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return times;
}

signed main(){
    for(int i = 1 ; i <= 51 ; ++i)
        inv[i] = poww(i , MOD - 2);
    int N = read() , K = read() , ans = 1;
    for(int i = 2 ; i * i <= N ; ++i)
        if(N % i == 0){
            int cnt = 0;
            while(N % i == 0){
                ++cnt;
                N /= i;
            }
            dp[0][0] = 1;
            int tms = i;
            for(int j = 1 ; j <= cnt ; ++j , tms = tms * i % MOD)
                dp[j][0] = (dp[j - 1][0] + tms) % MOD;
            for(int j = 1 ; j <= K ; ++j){
                dp[0][j] = 1;
                for(int k = 1 ; k <= cnt ; ++k)
                    dp[k][j] = (dp[k][j - 1] * inv[k + 1] + dp[k - 1][j]) % MOD;
            }
            ans = ans * (dp[cnt][K] - dp[cnt - 1][K] + MOD) % MOD;
        }
    if(N != 1)
        ans = ans * ((poww(poww(2 , K) , MOD - 2) * (N % MOD) + MOD + 1 - (poww(poww(2 , K) , MOD - 2))) % MOD) % MOD;
    cout << ans;
    return 0;
}