• UOJ #450. 【集训队作业2018】复读机


    前置知识单位根反演自己去浅谈单位根反演看(此外可能需要一定的生成函数的姿势)

    首先一看(d)这么小,那我们来分类讨论一下吧

    (d=1)时,显然答案就是(k^n)

    (d=2)时,如果你知道可重排列的指数型生成函数:

    [G(x)=sum_{i=0} frac{x^{2i}}{(2i)!} ]

    那么就跳过以下部分直接去看转化,我们来推导一下这个生成函数

    直接搞一个DP,设(f_{i,j})表示前(i)个复读机选了(j)个时间的方案数,转移的时候枚举这个复读机复读了几次

    [f_{i,j}=sum_{k=0}^j [2|k] C_{n-(j-k)}^k f_{i-1,j-k} ]

    (f_i)看做一个指数型生成函数,那么每次加入一个复读机相当于乘上了一个上面的(sum_{i=0} [2|i] frac{x^i}{i!})

    由于我们这里的生成函数没有考虑每次操作间的顺序,因此乘上(n!)有:

    [Ans=n!cdot G(x)^k[x^n] ]

    然后这个(G(x))细看有点熟悉,稍加推导会发现它就是(frac{e^x+e^{-x}}{2}),那么这里还是直接用二项式定理展开

    [Ans=n!cdot (frac{(e^x+e^{-x})^k}{2^k})=n!cdot(frac{sum_{i=0}^k C_k^i cdot e^{{2i-k}x}}{2^k}) ]

    然后我们求([x^n]),泰勒逆展开之后会发现分母里的(n!)和前面的(n!)抵消了,因此

    [Ans=frac{sum_{i=0}^k C_k^icdot (2i-k)^n}{2^k} ]

    直接(O(k))计算即可

    (d=3)时,和上面类似我们可以直接得出此时的(G(x)=sum_{i=0} [3|i] frac{x^i}{i!}),然后来一发单位根反演:

    [G(x)=sum_{i=0}frac{1}{3}sum_{j=0}^2 frac{omega_3^{ij}cdot x^i}{i!} ]

    [=frac{1}{3}sum_{j=0}^2 sum_{i=0}frac{(omega_3^jcdot x)^i}{i!} ]

    快乐地泰勒逆展开一下就有:

    [G(x)=frac{1}{3}sum_{j=0}^2 e^{omega_3^jx} ]

    然后还是那个式子:

    [Ans=n!cdot G(x)^k[x^n] ]

    [=n!cdot (frac{sum_{a+b+c=k} (e^{(aomega_3^0+bomega_3^1+comega_3^2)x})cdot frac{k!}{a!b!c!}}{3^k}) ]

    还是泰勒逆展开,最后就有:

    [Ans=frac{sum_{a+b+c=k} (aomega_3^0+bomega_3^1+comega_3^2)cdot frac{k!}{a!b!c!}}{3^k} ]

    然后我们会发现(d=2)的情况其实也可以这么做,不过由于此时后面那个系数就是组合数,而且此时单位根就是(pm 1),因此也可以推回上面的式子

    最后说句闲话,这道题用(d=3)时的方法推一推就可以得到一个广泛的做法,此时的复杂度是(O(k^{d-1}))

    打了好多公式累死了233

    #include<cstdio>
    #define RI register int
    #define CI const int&
    using namespace std;
    const int N=500005,mod=19491001;
    int n,k,d,fact[N],inv[N],ans,cnt,pri[100],w0,w1,w2;
    inline int quick_pow(int x,int p=mod-2,int mul=1)
    {
    	for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
    }
    inline void inc(int &x,CI y)
    {
    	if ((x+=y)>=mod) x-=mod;
    }
    
    inline void init(CI n)
    {
    	RI i; for (fact[0]=i=1;i<=n;++i) fact[i]=1LL*fact[i-1]*i%mod;
    	for (inv[n]=quick_pow(fact[n]),i=n-1;~i;--i) inv[i]=1LL*inv[i+1]*(i+1)%mod;
    }
    inline int C(CI n,CI m)
    {
    	return 1LL*fact[n]*inv[m]%mod*inv[n-m]%mod;
    }
    inline int getroot(CI p)
    {
    	RI i,j; int x=p-1; for (i=2;i*i<=x;++i) if (x%i==0)
    	for (pri[++cnt]=i;x%i==0;x/=i); for (i=2;;++i)
    	{
    		bool flag=1; for (j=1;j<=cnt;++j)
    		if (quick_pow(i,(p-1)/pri[j])==1) { flag=0; break; }
    		if (flag) return quick_pow(i,(mod-1)/3);
    	}
    }
    int main()
    {
    	RI i,j; scanf("%d%d%d",&n,&k,&d); switch (d)
    	{
    		case 1:
    			printf("%d",quick_pow(k,n)); break;
    		case 2:
    			for (init(k),i=0;i<=k;++i) inc(ans,1LL*C(k,i)*quick_pow(2*i-k,n)%mod);
    			printf("%d",1LL*ans*quick_pow(2,mod-1-k)%mod); break;
    		case 3:
    			w0=1; w1=getroot(mod); w2=1LL*w1*w1%mod; init(k);
    			for (i=0;i<=k;++i) for (j=0;i+j<=k;++j)
    			inc(ans,1LL*quick_pow((1LL*w0*i%mod+1LL*w1*j%mod+1LL*w2*(k-i-j)%mod)%mod,n)*
    			fact[k]%mod*inv[i]%mod*inv[j]%mod*inv[k-i-j]%mod);
    			printf("%d",1LL*ans*quick_pow(3,mod-1-k)%mod); break;
    	}
    	return 0;
    }
    
  • 相关阅读:
    TCHAR转化为UTF8
    Chromium ID 计算方法
    构建之法感悟
    项目名称:上海地铁游
    统一入口的Ajax验证
    基于用户体验的服务型政府网站群建设优化方案
    新技术下的政府门户网站群建设建议
    国内CMS技术发展的外在表现形式
    JavaScript基础 BOM
    JavaScript基础 常见DOM树操作
  • 原文地址:https://www.cnblogs.com/cjjsb/p/11726832.html
Copyright © 2020-2023  润新知