uoj450 【集训队作业2018】复读机(生成函数,单位根反演)
题解时间
首先直接搞出单个复读机的生成函数 $ sumlimits_{ i = 0 }^{ k } [ d | i ] frac{ x^{ i } }{ i! } $ 。
容易想到直接上单位根反演:
[egin{aligned}
sumlimits_{ i = 0 }^{ k } [ d | i ] frac{ x^{ i } }{ i! }
& = sumlimits_{ i = 0 }^{ k } frac{ 1 }{ d } sumlimits_{ j = 0 }^{ d - 1 } omega_{ d }^{ ij } frac{ x^{ i } }{ i! } \
& = frac{ 1 }{ d } sumlimits_{ j = 0 }^{ d - 1 } sumlimits_{ i = 0 }^{ k } frac{ ( omega_{ d }^{ j } x )^{ i } }{ i! } \
& = frac{ 1 }{ d } sumlimits_{ j = 0 }^{ d - 1 } e^{ ( omega_{ d }^{ j } x )^{ i } }
end{aligned}
]
然后答案就是 $ [ x^{ n } ] ( frac{ 1 }{ d^{ k } } ( sumlimits_{ j = 0 }^{ d - 1 } e^{ omega_{ d }^{ j } x } )^{ k } ) $ 。
由于 $ d le 3 $ ,所以直接大力二项式定理,时间复杂度 $ O( d k^{d-1} log{ k } ) $ 。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long lint;
struct pat{int x,y;pat(int x=0,int y=0):x(x),y(y){}bool operator<(const pat &p)const{return x==p.x?y<p.y:x<p.x;}};
template<typename TP>inline void read(TP &tar)
{
TP ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){ret=ret*10+(ch-'0');ch=getchar();}
tar=ret*f;
}
template<typename TP,typename... Args>inline void read(TP& t,Args&... args){read(t),read(args...);}
namespace RKK
{
const int N=500011;
const int mo=19491001;
const int g=7,om=18827933;
void doadd(int &a,int b){if((a+=b)>=mo) a-=mo;}int add(int a,int b){return (a+=b)>=mo?a-mo:a;}
void dodec(int &a,int b){doadd(a,mo-b);}int dec(int a,int b){return add(a,mo-b);}
void domul(int &a,int b){a=1ll*a*b%mo;}int mul(int a,int b){return 1ll*a*b%mo;}
int fpow(int a,int p){int ret=1;while(p){if(p&1) domul(ret,a);domul(a,a),p>>=1;}return ret;}
int inv[N],fac[N],ifac[N];
void init()
{
inv[1]=1;for(int i=2;i<=500000;i++) inv[i]=mul(inv[mo%i],mo-mo/i);
for(int i=fac[0]=1;i<=500000;i++) fac[i]=mul(fac[i-1],i);
for(int i=ifac[0]=1;i<=500000;i++) ifac[i]=mul(ifac[i-1],inv[i]);
}
int C(int n,int m){if(n<m||n<0||m<0) return 0;return mul(fac[n],mul(ifac[n-m],ifac[m]));}
int n,m,d,ans;
int main()
{
init();
read(n,m,d);
switch(d)
{
case 1:
ans=fpow(m,n);
break;
case 2:
for(int i=0;i<=m;i++) doadd(ans,mul(C(m,i),fpow(dec(i*2,m),n)));
break;
case 3:
for(int i=0;i<=m;i++)for(int j=0;i+j<=m;j++)
doadd(ans,mul(mul(C(m,i),C(m-i,j)),fpow(add(m-i-j,add(mul(om,i),mul(mul(om,om),j))),n)));
break;
}
domul(ans,fpow(inv[d],m));
printf("%d
",ans);
return 0;
}
}
int main(){return RKK::main();}