UOJ#450. 【集训队作业2018】复读机(EGF+单位根反演)

本文介绍了如何使用单位根反演解决UOJ#450复读机问题,指出当d≤3时,可以通过暴力展开和组合数计算系数来求解。并提供了相关代码实现。
摘要由CSDN通过智能技术生成

传送门
蒟蒻的第一道单位根反演,感觉还挺好用的

考虑对于每个复读机列出生成函数:
F = ∑ i ≥ 0 [ d ∣ i ] x i i ! F = ∑ i ≥ 0 x i i ! ∑ j = 1 d ( ω d i ) j d F = 1 d ∑ j = 1 d ∑ i ≥ 0 ( ω d j x ) i F = 1 d ∑ i = 1 d e ω d i x A n s = F k = 1 d k ( ∑ i = 1 d e ω d i x ) k \begin{aligned}F=&\sum_{i\ge0}[d|i]\frac{x^i}{i!}\\F=&\sum_{i\ge0}\frac{x^i}{i!}\frac{\sum_{j=1}^d(\omega_d^i)^j}{d}\\F=&\frac1d\sum_{j=1}^d\sum_{i\ge0}(\omega_d^jx)^i\\F=&\frac1d\sum_{i=1}^de^{\omega_d^ix}\\Ans=&F^k=\frac1{d^k}(\sum_{i=1}^de^{\omega_d^ix})^k\end{aligned} F=F=F=F=Ans=i0[di]i!xii0i!xidj=1d(ωdi)jd1j=1di0(ωdjx)id1i=1deωdixFk=dk1(i=1deωdix)k
我们发现这个 d ≤ 3 d\le3 d3,那么暴力 d d d项式展开用组合数计算系数即可。
代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int mod=19491001,w3=18827933;
typedef long long ll;
inline int add(int a,int b){return (a+=b)<mod?a:a-mod;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline void Add(int&a,int b){(a+=b)<mod?a:a-=mod;}
inline void Dec(int&a,int b){(a-=b)<0?a+=mod:a;}
inline void Mul(int&a,int b){a=(ll)a*b%mod;}
inline int ksm(int a,int p){int ret=1;for(;p;p>>=1,Mul(a,a))if(p&1)Mul(ret,a);return ret;}
const int N=5e6+5;
int n,k,d,fac[N],ifac[N];
inline void init_fac(){
	fac[0]=ifac[0]=fac[1]=ifac[1]=1;
	for(ri i=2;i<=k;++i)fac[i]=mul(fac[i-1],i),ifac[i]=mul(ifac[mod-mod/i*i],mod-mod/i);
	for(ri i=2;i<=k;++i)Mul(ifac[i],ifac[i-1]);
}
inline int C(int n,int m){return(ll)fac[n]*ifac[m]%mod*ifac[n-m]%mod;}
int main(){
	cin>>n>>k>>d;
	if(n!=n/d*d)return puts("0"),0;
	if(d==1)return cout<<ksm(k,n),0;
	init_fac();
	if(d==2){
		int res=0;
		for(ri i=0;i<=k;++i)Add(res,mul(C(k,i),ksm(dec(2*i,k),n)));
		cout<<mul(res,ksm(ksm(2,mod-2),k));
		return 0;
	}
	int a=1,b=w3,c=mul(b,b),res=0;
	for(ri i=0,t=0;i<=k;++i,t=0){
		for(ri j=0,up=k-i;j<=up;++j)Add(t,mul(C(k-i,j),ksm(add(mul(a,i),add(mul(b,j),mul(c,k-i-j))),n)));
		Add(res,mul(t,C(k,i)));
	}
	cout<<mul(res,ksm(ksm(3,mod-2),k));
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值