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

谢谢!!!

发布了117 篇原创文章 · 获赞 154 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Tan_tan_tann/article/details/105407284