Makoto and a Blackboard

Makoto and a Blackboard

題解

我們定義F\left(n,k \right )爲n操作k次的期望個數,那麼O\left(\sqrt{n} \right )F\left(n,k \right )= \sum_{d|n}\frac{1}{x}F\left(d,k-1 \right ),其中x爲d的約數個數。

而n的約數個數可以在O\left(\sqrt{n} \right )的時間內求出,於是總時間就是O\left(k\sqrt{n} \right )

對於一個質數n,答案是\frac{n+2^{k}-1}{2^{k}}

那麼對於n= p^{x},其中p爲質數。那麼就可以用dp來解決這個問題。

dp_{i,j}表示經過i次操作,數變爲p^{j}的概率。

可得轉移方程式爲dp_{i,j}=\sum_{k=j}^{x}\frac{1}{j}dp_{i-1,k}

而答案就爲\sum_{j=1}^{x}p^j\cdot dp_{k,j}

因爲這是一個積性函數,所以可得答案sum_{i,jk}=sum_{i,j}\cdot sum_{i,k} ((j,k)==1)

於是,我們把n分解質因數後的答案乘起來即可。

於是就可以以O\left(\sqrt{n}+k\cdot log_{n}^{3} \right )的時間複雜度求出來了。

源碼

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
#define MAXN 1000005
typedef long long LL;
#define int LL
const LL mo=1e9+7;
typedef pair<double,int> pii;
#define gc() getchar()
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=gc();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=gc();}
	while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=gc();}
	x*=f;
}
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
int n,m,prime[MAXN],cntp,ans,sum;
int dis[MAXN],dp[10005][50],inv[65];
void init(int x){
	for(int i=2;i*i<=x;i++){
		if(x%i==0)prime[++cntp]=i;
		while(x%i==0)x/=i,++dis[cntp];
	}
	if(x!=1)prime[++cntp]=x,dis[cntp]++; 
}
int qkpow(int a,int s){
	int t=1;
	while(s){
		if(s&1)t=t*a%mo;
		s>>=1;a=a*a%mo;
	}
	return t;
}
signed main(){
	read(n);read(m);init(n);ans=1;
	for(int i=1;i<=60;i++)inv[i]=qkpow(i,mo-2);
	for(int T=1;T<=cntp;T++){
		memset(dp,0,sizeof(dp));
		dp[0][dis[T]]=1;int sum=0;
		for(int i=1;i<=m;i++)
			for(int j=0;j<=dis[T];j++)
				for(int k=j;k<=dis[T];k++)
					dp[i][j]=(dp[i-1][k]*inv[k+1]%mo+dp[i][j])%mo;
		for(int i=0;i<=dis[T];i++){
			sum=(sum+dp[m][i]*qkpow(prime[T]%mo,i)%mo)%mo;
			//printf("%d %d:%d\n",m,i,dp[m][i]);	
		}
		ans=ans*sum%mo;
	}
	printf("%lld",ans);
	return 0;
}

謝謝!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章