Codeforces 1097D. Makoto and a Blackboard

传送门

首先考虑如果 $n$ 只有一个质因数的情况,即 $n=p^t$

那么显然可以 $dp$ ,设 $f[i][j]$ 表示第 $i$ 步,当前剩下 $p^j$ 的概率

那么转移很简单: $f[i][j]=\sum_{k=j}^{t}\frac{f[i-1][k]}{k+1}$ ,然后可以发现 $f[i][j+1]$ 算的在 $f[i][j]$ 里面都会算到,那么可以把转移优化一下:

$f[i][j]=f[i][j+1]+\frac{f[i-1][j]}{j+1}$ ,然后复杂度就很稳

现在考虑一下 $n=\prod_{i=1}^{m} p_{i} ^ {t_i}$ 的情况,发现直接把每个质数的贡献分别算然后乘起来即可

可以这样考虑,首先概率显然是可以乘起来的,然后发现当两件事情同时发生:剩下 $p_{x} ^ {a}$ 和剩下 $p_{y} ^ {b}$ 

贡献即为$p_{x} ^ {a} p_{y} ^ {b} $ ,发现刚好也是相乘的,所以直接相乘即可

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
inline ll read()
{
    ll x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=233,M=1e4+7,mo=1e9+7;
inline int fk(int x) { return x>=mo ? x-mo : x; }
ll n,m;
int p[N],cnt[N],inv[N],tot;
int f[M][N],Ans=1;
int main()
{
    n=read(),m=read();
    int T=sqrt(n); ll now=n;
    for(int i=2;i<=T;i++)
    {
        if(now%i) continue;
        p[++tot]=i; while(now%i==0) cnt[tot]++,now/=i;
    }
    if(now>1) p[++tot]=now%mo,cnt[tot]=1;
    inv[1]=1;
    for(int i=2;i<N;i++)
        inv[i]=1ll*(mo-mo/i)*inv[mo%i]%mo;
    for(int i=1;i<=tot;i++)
    {
        memset(f,0,sizeof(f)); f[0][cnt[i]]=1;
        for(int j=1;j<=m;j++)
        {
            f[j][cnt[i]]=1ll*f[j-1][cnt[i]]*inv[cnt[i]+1]%mo;
            for(int k=cnt[i]-1;k>=0;k--)
                f[j][k]=fk(f[j][k+1]+1ll*f[j-1][k]*inv[k+1]%mo);
        }
        int pw=1,res=0;
        for(int j=0;j<=cnt[i];j++)
        {
            res=fk(res+1ll*f[m][j]*pw%mo);
            pw=1ll*pw*p[i]%mo;
        }
        Ans=1ll*Ans*res%mo;
    }
    printf("%d\n",Ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/LLTYYC/p/11730823.html