给定一个正整数 ,每次等概率从 的所有因子中选择一个,设其为 ,将 变为 。
求期望多少次 变为 ,对 取模。
,输入会给出 的所有不同的质因子 。
设 表示 时的答案,那么有:
设 ,那么显然可重集 相同的 的 是相同的。
注意到由于 是可重集,所以不妨钦定 ,不同的 最多只有 个,实际上只有大概 个。
那么设 为可重集为 时的答案,则转移是一个高维前缀和,可以设 ,则有转移:
则 。
由于转移需要的是 ,所以不妨先令 ,做完高维前缀和再加回去。
时间复杂度 。
代码如下:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <map>
using namespace std;
const int SS=105,STS=200005,S=25,p=1000000007;
struct sta
{
vector<int> v;
inline void push(int x){v.push_back(x);}
inline int size(){return v.size();}
inline void sort(){::sort(v.begin(),v.end());}
inline int& operator[](int x){return v[x];}
inline void delbeg(){v.erase(v.begin());}
inline bool operator<(const sta &b)const
{
if(v.size()!=b.v.size()) return v.size()<b.v.size();
for(int i=0;i<v.size();i++) if(v[i]!=b.v[i]) return v[i]<b.v[i];
return false;
}
};
char str[SS];
__int128 n,a[S];
int m;
int tot;
map<sta,int> idx;
int f[STS][S];
inline int qpow(int x,int y)
{
int res=1;
for(;y>0;y>>=1,x=1ll*x*x%p) res=y&1?1ll*res*x%p:res;
return res;
}
int DP(sta &st)
{
if(idx.find(st)!=idx.end()) return f[idx[st]][0];
idx[st]=++tot;
int id=tot;
if(st.size()==0) return f[id][0]=0;
for(int i=1;i<=st.size();i++)
{
sta nst=st;
nst[i-1]--,nst.sort();
if(nst[0]!=0) DP(nst),f[id][i]=(f[id][i-1]+f[idx[nst]][i])%p;
else nst.delbeg(),DP(nst),f[id][i]=(f[id][i-1]+f[idx[nst]][i-1])%p;
}
int ml=1;
for(int i=0;i<st.size();i++) ml=1ll*ml*(st[i]+1)%p;
f[id][0]=1ll*qpow(ml-1+p,p-2)*(f[id][st.size()]+ml)%p;
for(int i=1;i<=st.size();i++) f[id][i]=(f[id][i]+f[id][0])%p;
return f[id][0];
}
int main()
{
freopen("div.in","r",stdin);
freopen("div.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
while(cin>>str>>m)
{
int len=strlen(str);
n=0;
for(int i=0;i<len;i++) n=n*10+str[i]-'0';
sta st;
for(int i=1;i<=m;i++)
{
cin>>str;
len=strlen(str);
a[i]=0;
for(int j=0;j<len;j++) a[i]=a[i]*10+str[j]-'0';
int cnt=0;
while(n%a[i]==0) n/=a[i],cnt++;
st.push(cnt);
}
st.sort();
cout<<DP(st)<<'\n';
}
return 0;
}