zoukankan      html  css  js  c++  java
  • 【UOJ450】【集训队作业2018】复读机(生成函数+单位根反演)

    点此看题面

    • 求有多少长度为(n)、值域为([1,k])的整数数列,满足所有数的出现次数都是(d)的倍数。
    • (nle10^9)(kle5 imes10^5,dle2)(kle10^3,dle3)

    指数型生成函数

    考虑用一个指数型生成函数(F(x))来表示每个数填(i)个的方案数,那么最终答案就应该是:

    [[frac{x^n}{n!}]F(x)^k ]

    而这个生成函数其实是非常显然的,就是(sumfrac{x^i}{i!})只保留(d)的倍数项:

    [F(x)=sum_{i=0}^{+infty}[d|i]frac{x^i}{i!} ]

    单位根反演

    考虑单位根反演的式子:

    [[d|i]=frac1dsum_{j=0}^{d-1}omega_d^{ij} ]

    代入就可以得到:

    [F(x)=frac1dsum_{j=0}^{d-1}sum_{i=0}^{+infty}frac{(omega_d^jx)^i}{i!} ]

    发现后面的(sum)中的一项可以直接看作(e)的幂次,因此得到:

    [F(x)=frac1dsum_{j=0}^{d-1}e^{omega_d^jx} ]

    暴力枚举

    要求(F(x)^k),先提出每一项的(frac 1d)共计((frac1d)^k),而剩余部分我们只需要考虑每次选的(e^{omega_d^jx})(j)是多少。

    不妨直接枚举选择了(i_j)(e^{omega_d^j}x),那么最终答案就应该是:

    [[frac{x^n}{n!}](sum_{sum_{j=0}^{d-1}i_j=k}frac{k!}{prod_{j=0}^{d-1}i_j!}e^{(sum_{j=0}^{d-1}i_j imes omega_d^j)x}) ]

    前面是一堆系数,其实只用考虑(e^{(sum_{j=0}^{d-1}i_j imes omega_d^j)x})(n)次项系数然后乘上(n!),于是得到:

    [sum_{sum_{j=0}^{d-1}i_j=k}frac{k!}{prod_{j=0}^{d-1}i_j!}(sum_{j=0}^{d-1}i_j imes omega_d^j)^n ]

    所以说具体实现只要暴力枚举所有(i_j)即可。

    代码:(O(k^{d-1}logn))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define K 500000
    #define X 19491001
    #define PR 7//预先算出19491001的原根是7
    using namespace std;
    int n,k,d;I int QP(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
    int Fac[K+5],IFac[K+5];I void InitFac(CI S)//预处理阶乘和阶乘逆元
    {
    	RI i;for(Fac[0]=i=1;i<=S;++i) Fac[i]=1LL*Fac[i-1]*i%X;
    	for(IFac[i=S]=QP(Fac[S],X-2);i;--i) IFac[i-1]=1LL*IFac[i]*i%X;
    }
    int main()
    {
    	if(scanf("%d%d%d",&n,&k,&d),d==1) return printf("%d
    ",QP(k,n)),0;//d=1,答案其实就是k^n
    	RI i,j,t=0;if(InitFac(k),d==2)//d=2
    	{
    		for(i=0;i<=k;++i) t=(t+1LL*Fac[k]*IFac[i]%X*IFac[k-i]%X*QP((2*i-k+X)%X,n))%X;//枚举有i个1,k-1个-1
    		return printf("%d
    ",1LL*t*QP(QP(d,X-2),k)%X),0;//注意乘上(1/d)^k
    	}
    	RI w=QP(PR,(X-1)/3),w2=1LL*w*w%X;for(i=0;i<=k;++i) for(j=0;j<=k-i;++j)//枚举有i个w,j个w2,k-i-j个1
    		t=(t+1LL*Fac[k]*IFac[i]%X*IFac[j]%X*IFac[k-i-j]%X*QP((1LL*i*w+1LL*j*w2+(k-i-j))%X,n))%X;
    	return printf("%d
    ",1LL*t*QP(QP(d,X-2),k)%X),0;//注意乘上(1/d)^k
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    (转)动态SQL和PL/SQL的EXECUTE IMMEDIATE选项
    MyBase代码
    LinkedList、ArrayList、Vector
    MyEclipse8.5的Help菜单下没有Software Updates的设置方法
    球星们
    文件内容提取到byte数组里
    List<>Array
    ArcGIS9.3全套下载地址
    administrator用户不见了
    ArcEngine VS2005 C#
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/UOJ450.html
Copyright © 2011-2022 走看看