LOJ6696 复读机 加强版

Link
考虑单个元素的EGF,显然为(f(x)=sumlimits_{ige0}[d|i]frac{x^i}{i!}=frac1dsumlimits_{i=0}^{d-1}exp(omega_d^ix))
那么答案就是([x^n]f(x)^k)
考虑分圆多项式(Phi_d(x)=prodlimits_{kin[0,d)wedgegcd(d,k)=1}(x-omega_d^k)=prodlimits_{k|d}(x^{frac dk}-1)^{mu(k)})
那么(omega_d^k=(x^kmodPhi_d(x))mid_{x=omega})
很显然(deg(Phi_d(x))=varphi(d)),且(Phi_d(x))的系数都是整数,因此(omega_d^k)可以由(omega_d^0,cdots,omega_d^{varphi(d)-1})以整数线性表示。
实际上可以证明,对于域(mathbb N)上的线性空间(V=operatorname{span}(omega_d^0,cdots,omega_d^{d-1}))一定有(dim V=varphi(d))
这样我们就可以把(f(x))写成(F(exp x,exp(omega x),cdots,exp(omega_d^{d-1}x)))的形式了。
(G=F^k),那么(Ffrac{partial G}{partial x}=kGfrac{partial F}{partial x})
由这个式子列出递推式然后解得系数是trivial的。
时间复杂度为(O(k^{varphi(d)}log n))(log n)是快速幂的。
(d=2)时可以通过线性筛幂函数做到(O(k))

#include<cstdio>
using i64=long long;
const int N=2007,P=19491001;
int n,k,d;i64 w,ans,fac[N],ifac[N],inv[N];
int abs(int x){return x<0? -x:x;}
void inc(i64&a,i64 b){a+=b-P,a+=a>>63&P;}
i64 pow(i64 a,i64 b){i64 c=1;for(a%=P;b;b>>=1,a=a*a%P)if(b&1)c=c*a%P;return c;}
i64 binom(int n,int m){return fac[n]*ifac[m]%P*ifac[n-m]%P;}
void init(int n=2000)
{
    fac[0]=ifac[0]=inv[0]=fac[1]=ifac[1]=inv[1]=1,w=pow(7,(P-1)/d);
    for(int i=2;i<=n;++i) fac[i]=i*fac[i-1]%P,inv[i]=(P-P/i)*inv[P%i]%P,ifac[i]=inv[i]*ifac[i-1]%P;
}
namespace Sub1
{
    void solve()
    {
	for(int a=0;a<=k;++a) for(int b=2-((k^a)&1);a+b<=k;b+=2) inc(ans,pow(a*w+b,n)*binom(k,(k+a+b)/2)%P*binom(k,(k+abs(a-b))/2)%P);
	printf("%lld",4*pow(d,P-k-1)*ans%P);
    }
}
namespace Sub2
{
    i64 a[N][N],b[N][N];
    void solve()
    {
	for(int i=0;i<=k;++i) a[0][i]=a[i][0]=binom(k,i),b[i][0]=i*a[i][0]%P;
	for(int i=1;i<=k+k;++i)
	    for(int j=1;j<=i&&j<=k;++j)
	    {
		i64 x=k*a[i-1][j]-b[i-1][j]-b[i][j-1];
		if(j>=2) x+=k*a[i-1][j-2]-b[i-1][j-2];
		if(i>=2) x+=2*k*a[i-2][j-1]-b[i-2][j-1];
		if(i>=2&&j>=2) x+=2*k*a[i-2][j-2]-b[i-2][j-2];
		x=(x+4*P)%P,b[i][j]=x,a[i][j]=inv[i]*x%P;
		if(i<=k) a[j][i]=a[i][j],b[j][i]=j*a[j][i]%P;
	    }
	for(int i=0;i<=k+k;++i) for(int j=0;j<=k;++j) inc(ans,(j==k? 1:2)*pow((P+i-k)*w+k-j,n)*a[i][j]%P);
	printf("%lld",ans*pow(d,P-k-1)%P);
    }
}
int main()
{
    scanf("%d%d%d",&n,&k,&d),init();
    if(n%d) puts("0"); else if(d==4) Sub1::solve(); else if(d==6) Sub2::solve();
}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12957630.html