[CF1097D]Makoto and a Blackboard

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;
}

posted @ 2019-03-12 12:56  cloud_9  阅读(151)  评论(0编辑  收藏  举报