uoj450 【集训队作业2018】复读机(生成函数,单位根反演)

uoj450 【集训队作业2018】复读机(生成函数,单位根反演)

uoj

题解时间

首先直接搞出单个复读机的生成函数 $ \sum\limits_{ i = 0 }^{ k } [ d | i ] \frac{ x^{ i } }{ i! } $ 。

容易想到直接上单位根反演:

\[\begin{aligned} \sum\limits_{ i = 0 }^{ k } [ d | i ] \frac{ x^{ i } }{ i! } & = \sum\limits_{ i = 0 }^{ k } \frac{ 1 }{ d } \sum\limits_{ j = 0 }^{ d - 1 } \omega_{ d }^{ ij } \frac{ x^{ i } }{ i! } \\ & = \frac{ 1 }{ d } \sum\limits_{ j = 0 }^{ d - 1 } \sum\limits_{ i = 0 }^{ k } \frac{ ( \omega_{ d }^{ j } x )^{ i } }{ i! } \\ & = \frac{ 1 }{ d } \sum\limits_{ j = 0 }^{ d - 1 } e^{ ( \omega_{ d }^{ j } x )^{ i } } \end{aligned} \]

然后答案就是 $ [ x^{ n } ] ( \frac{ 1 }{ d^{ k } } ( \sum\limits_{ 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\n",ans);
	return 0;
}
}
int main(){return RKK::main();}
posted @ 2020-07-26 11:36  RikukiIX  阅读(197)  评论(0编辑  收藏  举报