zoukankan      html  css  js  c++  java
  • P4491 [HAOI2018]染色

    传送门

    我觉得自己的数学也是够差的……一点思路也没有……

    考虑容斥,首先(lim=min(m,n/S)),设(f[i])表示出现恰好(S)次的元素大于等于(i)种的情况,我们随便选(i)种颜色放(S)次,选的方法数有(C_m^i)种,然后染色可以看做是一个类似全排列的东西,每连续的几个染上同样的颜色,那么方案数为(frac{n!}{(S!)^i(n-S*i)!}),前面颜色已经选定了,后面的每个有(m-i)种颜色可选,所以还要乘上一个((m-i)^{n-S*i})

    综上,可得$$f_i=C_m^ifrac{n!}{(S!)^i(n-Si)!}(m-i)^{n-Si}$$
    然后考虑容斥,设(g_i)表示元素个数恰好等于(i)的情况总数,那么根据容斥原理,有$$g_i=sum_{j=i}^{lim}(-1)^{j-i}C_j^if_j$$
    然后开始推柿子$$g_i=sum_{j=i}^{lim}frac{(-1)^{j-i}j!}{i!(j-i)!}f_j$$

    [g_ii!=sum_{j=i}^{lim}frac{(-1)^{j-i}}{(j-i)!}f_jj_! ]

    于是定义多项式(F_i=f_jj!)(A_i=frac{(-1)^{n-i}}{(n-i)!})(G_{i+lim}=g_ii!),那么不难发现上面那个式子其实是个卷积,即$$G_{lim+i}=sum_{j+k=lim+i}A_jF_k$$

    于是用(NTT)计算出(G),然后更新答案即可

    //minamoto
    #include<bits/stdc++.h>
    #define R register
    #define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
    #define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
    #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
    using namespace std;
    char buf[1<<21],*p1=buf,*p2=buf;
    inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
    int read(){
        R int res,f=1;R char ch;
        while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
        for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
        return res*f;
    }
    char sr[1<<21],z[20];int K=-1,Z=0;
    inline void Ot(){fwrite(sr,1,K+1,stdout),K=-1;}
    void print(R int x){
        if(K>1<<20)Ot();if(x<0)sr[++K]='-',x=-x;
        while(z[++Z]=x%10+48,x/=10);
        while(sr[++K]=z[Z],--Z);sr[++K]='
    ';
    }
    const int N=5e5+5,M=1e7+5,P=1004535809,Gi=334845270;
    inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
    inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
    inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
    int ksm(R int x,R int y){
    	R int res=1;
    	for(;y;y>>=1,x=mul(x,x))if(y&1)res=mul(res,x);
    	return res;
    }
    int A[N],B[N],w[N],fac[M],inv[M],r[N],O[N],n,m,S,lim,len=1,l,ans;
    inline int C(R int n,R int m){
    	if(m>n)return 0;
    	return mul(fac[n],mul(inv[m],inv[n-m]));
    }
    void init(){
    	inv[0]=fac[0]=fac[1]=1;fp(i,2,lim)fac[i]=mul(fac[i-1],i);
    	inv[lim]=ksm(fac[lim],P-2);fd(i,lim-1,1)inv[i]=mul(inv[i+1],i+1);
    }
    void NTT(int *A,int ty){
    	fp(i,0,len-1)if(i<r[i])swap(A[i],A[r[i]]);
    	for(R int mid=1;mid<len;mid<<=1){
    		R int I=(mid<<1),Wn=ksm(ty==1?3:Gi,(P-1)/I);O[0]=1;
    		fp(i,1,mid-1)O[i]=mul(O[i-1],Wn);
    		for(R int j=0;j<len;j+=I)for(R int k=0;k<mid;++k){
    			int x=A[j+k],y=mul(O[k],A[j+k+mid]);
    			A[j+k]=add(x,y),A[j+k+mid]=dec(x,y);
    		}
    	}if(ty==-1)for(R int i=0,inv=ksm(len,P-2);i<len;++i)A[i]=mul(A[i],inv);
    }
    int main(){
    //	freopen("testdata.in","r",stdin);
    	n=read(),m=read(),S=read(),lim=max(n,m);
    	init();fp(i,0,m)w[i]=read();lim=min(m,n/S);
    	fp(i,0,lim)A[i]=mul(C(m,i),mul(fac[n],mul(ksm(m-i,n-S*i),mul(fac[i],ksm(mul(ksm(fac[S],i),fac[n-S*i]),P-2)))));
    	fp(i,0,lim){
    		A[i]=mul(C(m,i),mul(fac[n],ksm(m-i,n-S*i)));
    		A[i]=mul(A[i],mul(fac[i],ksm(mul(ksm(fac[S],i),fac[n-S*i]),P-2)));
    	}
    	fp(i,0,lim){
    		B[i]=inv[lim-i];
    		if((lim-i)&1)B[i]=P-B[i];
    	}while(len<=lim+lim)len<<=1,++l;
    	fp(i,0,len-1)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    	NTT(A,1),NTT(B,1);
    	fp(i,0,len-1)A[i]=mul(A[i],B[i]);
    	NTT(A,-1);fp(i,0,lim)ans=add(ans,mul(w[i],mul(A[lim+i],inv[i])));
    	printf("%d
    ",ans);return 0;
    }
    
  • 相关阅读:
    poj 3243 Clever Y(BabyStep GiantStep)
    poj 2417 Discrete Logging
    poj 3481 Double Queue
    hdu 4046 Panda
    hdu 2896 病毒侵袭
    poj 1442 Black Box
    hdu 2815 Mod Tree
    hdu 3065 病毒侵袭持续中
    hdu 1576 A/B
    所有控件
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/10176843.html
Copyright © 2011-2022 走看看