Codeforces

Luogu

分析

容易想到设 $dp_{i,j}$ 表示 $j$ 次操作后 $i$ 的期望大小,转移直接枚举约数即可。然而这样子显然是会 T 的...

注意到当 $\gcd(i,j)=1$ 时有 $dp_{i\times j,k}=dp_{i,k}\times dp_{j,k}$,因此我们可以将 $n$ 分解为 $p_1\!^{c_1}p_2\!^{c_2}\cdots$ 的形式,然后将每个 $dp_{p_i\!^{c_i},k}$ 乘起来即可。

考虑如何计算 $dp_{p_i\!^{c_i},k}$ 。设 $f_{i,j}$ 表示 $j$ 次操作后 $p^i$ 的期望大小,转移时同样枚举约数。由于 $p^i$ 的约数仅有 $i+1$ 个,所以就能跑过去了。

代码

// ===================================
//   author: M_sea
//   website: http://m-sea-blog.com/
// ===================================
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#define re register
#define int long long
using namespace std;

inline int read() {
    int X=0,w=1; char c=getchar();
    while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
    while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
    return X*w;
}

const int mod=1e9+7;
inline int qpow(int a,int b) { int c=1;
    for (;b;b>>=1,a=1ll*a*a%mod) if (b&1) c=1ll*c*a%mod;
    return c;
}

int n,k;
int dp[60][10010];

inline int dfs(int p,int c,int k) {
    if (dp[c][k]) return dp[c][k];
    if (!c) return dp[c][k]=1;
    if (!k) return dp[c][k]=qpow(p,c);
    for (re int i=0;i<=c;++i)
        dp[c][k]=(dp[c][k]+dfs(p,i,k-1))%mod;
    return dp[c][k]=1ll*dp[c][k]*qpow(c+1,mod-2)%mod;
}

signed main() {
    n=read(),k=read(); int ans=1;
    for (re int i=2,c;i*i<=n;++i) {
        if (n%i) continue;
        for (c=0;n%i==0;++c,n/=i);
        memset(dp,0,sizeof(dp));
        ans=1ll*ans*dfs(i,c,k)%mod;
    }
    if (n>1) {
        memset(dp,0,sizeof(dp));
        ans=1ll*ans*dfs(n,1,k)%mod;
    }
    printf("%lld\n",ans);
    return 0;
}
最后修改:2021 年 03 月 23 日 10 : 28 PM