Description:
给定 (n,k),一共会进行 (k) 次操作,每次操作会把 (n) 等概率的变成 (n) 的某个约数
求操作 (k) 次后 (n) 的期望是多少,答案对 (10^9+7) 取模
Hint:
(n le 10^{15} ,k le 10^4)
Solution:
学到新姿势了
考虑裸暴力dp
(dp[i][k]=sum_{j|i}dp[j][k-1]*frac{1}{cnt})
显然T飞
我们发现答案满足积性
考虑把dp[i]拆成(dp[p_0^{a_0}]*dp[p_1^{a_1}]*dp[p_2^{a_2}]) 其中(p_i)为质数
这样状态数会大大减少,复杂度(O(k*log^2n))
暴力记搜就行
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ls p<<1
#define rs p<<1|1
using namespace std;
typedef long long ll;
const ll mxn=1e4+5,mod=1e9+7;
ll k,t,ans=1,dp[63][mxn];
ll n;
inline ll read() {
char c=getchar(); ll x=0,f=1;
while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
return x*f;
}
inline ll chkmax(ll &x,ll y) {if(x<y) x=y;}
inline ll chkmin(ll &x,ll y) {if(x>y) x=y;}
ll qpow(ll a,ll b)
{
ll res=1,bs=a;
while(b) {
if(b&1) res=1ll*res*bs%mod;
bs=1ll*bs*bs%mod;
b>>=1;
}
return res;
}
ll inv(ll x) {return qpow(x,mod-2);}
ll solve(ll a,ll cnt,ll opt)
{
if(cnt==0) {
dp[cnt][opt]=1;
return 1;
}
if(opt==0) {
if(!dp[cnt][opt]) dp[cnt][opt]=1ll*solve(a,cnt-1,opt)*a%mod;
return dp[cnt][opt];
}
ll res=0;
for(ll d=0;d<=cnt;++d) {
if(!dp[d][opt-1]) dp[d][opt-1]=solve(a,d,opt-1);
res=(res+dp[d][opt-1])%mod;
}
return (ll ) (1ll*res*inv(cnt+1)%mod);
}
int main()
{
scanf("%lld",&n); k=read();
for(ll i=2;i*i<=n;++i) {
if(n%i!=0) continue ; t=0;
while(n%i==0) ++t,n/=i;
memset(dp,0,sizeof(dp));
ans=1ll*ans*solve(i,t,k)%mod;
}
memset(dp,0,sizeof(dp));
if(n>1) ans=1ll*ans*solve(n,1,k)%mod;
printf("%lld",ans);
return 0;
}