[Codeforces1097D] Makoto and a Blackboard

链接:https://codeforces.com/contest/1097/problem/D

考虑一个暴力DP
f i , j f_{i,j} 表示到第i轮, 当前的数是 j j 的个数
j j 只有可能是 n n 的因数,最多大概是 2 w 2w
但是你会发现状态已经很大了,并且无法 O ( 1 ) O(1) 转移,GG!

于是考虑优化状态
我们可以对于质因数分开考虑
我们算出每一个质因数期望是什么,最后乘起来就是答案了
于是对于每一个质因数简单DP
f i , j f_{i,j} 表示到第 i i 轮,次数为 j j 的概率是什么
转移就暴力枚举上一次的次数是什么来转移及㐓了
次数显然很小, 2 60 2^{60} 就已经远远超出了,因此直接估算为60
至于不同质因数,大概20就远远超出了
因此,每次DP暴力转移就好了

我的代码已经十分暴力了。。
如果想跑得更快,可以在转移的时候加点前缀和后缀和什么的
就可以去掉一重循环
但是并没有必要。。
CODE:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const LL MOD=1e9+7;
const LL N=10005;
LL n,k;
LL ans=1;
LL f[N][61];
LL sum[61];
LL inv[61];
void calc (LL xx,LL x)
{
	f[0][x]=1;for (LL u=0;u<x;u++) f[0][u]=0;
	for (LL u=1;u<=k;u++)
	{
		for (LL i=0;i<=x;i++)
		{
			f[u][i]=0;
			for (LL j=i;j<=x;j++)
				f[u][i]=(f[u][i]+f[u-1][j]*inv[j+1]%MOD)%MOD;
		}
	}
	LL lalal=0,now=1;
	for (LL i=0;i<=x;i++)
	{
		lalal=(lalal+now*f[k][i]%MOD)%MOD;
		now=now*xx%MOD;
	}
	ans=ans*lalal%MOD;
}
int main()
{
	inv[1]=1;for (LL u=2;u<=60;u++) inv[u]=(MOD-MOD/u)*inv[MOD%u]%MOD;
	scanf("%lld%lld",&n,&k);
	for (LL u=2;u*u<=n;u++)
	{
		LL i=0;
		while (n%u==0)	{n/=u;i++;}
		if (i==0) continue;
		calc(u,i);
	}
	if (n!=1)	calc(n,1);
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36797743/article/details/85834812