zoukankan      html  css  js  c++  java
  • P4491 [HAOI2018]染色 广义容斥 NTT 生成函数

    LINK:染色

    算是比较常规的广义容斥。

    算恰好k个 可以直接转成至少k个。

    至少k个非常的好求 直接生成函数。

    (g_k)表示至少有k个颜色是满足的 那么有 (g_k=C(m,k)frac{n!}{(s!)^k}frac{(m-k)^{n-sk}}{(n-sk)!})

    (f_k)表示恰好有k个颜色是满足的 那么有 (f_k=sum_{j=k}C(j,k)(-1)^{j-k}g_j)

    前者可以直接求 后者需要卷积一下。

    坑点:模数不是998244353 是1004535809 原根也是3. NTT的时候 减法的时候由于数组中有的值可能为负数 所以此时需要也强制转换!

    const int MAXN=300010,maxn=10000010,GG=3;
    int n,m,s,lim,maxx;
    int w[MAXN],rev[MAXN],g[MAXN],f[MAXN];
    int inv[maxn],fac[maxn],O[MAXN];
    inline int ksm(int b,int p)
    {
    	int cnt=1;
    	while(p)
    	{
    		if(p&1)cnt=(ll)cnt*b%mod;
    		b=(ll)b*b%mod;p=p>>1;
    	}
    	return cnt;
    }
    inline int C(int a,int b)
    {
    	return a<b?0:(ll)fac[a]*inv[b]%mod*inv[a-b]%mod;
    }
    inline void NTT(int *a,int op)
    {
    	rep(1,lim-1,i)if(i<rev[i])swap(a[i],a[rev[i]]);
    	for(int len=2;len<=lim;len=len<<1)
    	{
    		int mid=len>>1;
    		int wn=ksm(GG,op==1?(mod-1)/len:mod-1-(mod-1)/len);
    		rep(1,mid,i)O[i]=(ll)O[i-1]*wn%mod;
    		for(int j=0;j<lim;j+=len)
    		{
    			rep(0,mid-1,i)
    			{
    				int x=a[i+j],y=(ll)a[i+j+mid]*O[i]%mod;
    				a[i+j]=(x+y)%mod;a[i+j+mid]=((ll)x-y+mod)%mod;
    			}
    		}
    	}
    	if(op==-1)
    	for(int i=0,INV=ksm(lim,mod-2);i<lim;++i)a[i]=(ll)a[i]*INV%mod;
    }
    signed main()
    {
    	//freopen("1.in","r",stdin);
    	get(n);get(m);get(s);O[0]=fac[0]=1;
    	rep(0,m,i)get(w[i]);maxx=max(max(s,m),n);
    	rep(1,maxx,i)fac[i]=(ll)fac[i-1]*i%mod;
    	inv[maxx]=ksm(fac[maxx],mod-2);
    	fep(maxx-1,0,i)inv[i]=(ll)inv[i+1]*(i+1)%mod;
    	int w2=1;
    	rep(0,m,k)
    	{
    		if(n<s*k)break;
    		g[k]=(ll)C(m,k)*fac[n]%mod*w2%mod;
    		g[k]=(ll)g[k]*ksm(m-k,n-s*k)%mod*inv[n-s*k]%mod;
    		w2=(ll)w2*inv[s]%mod;
    	}
    	rep(0,m,i)f[i]=((m-i)&1?-1:1)*inv[m-i],g[i]=(ll)fac[i]*g[i]%mod;
    	lim=1;while(lim<=m+m)lim=lim<<1;
    	rep(0,lim-1,i)rev[i]=rev[i>>1]>>1|(i&1?lim>>1:0);
    	NTT(f,1);NTT(g,1);
    	rep(0,lim-1,i)f[i]=(ll)f[i]*g[i]%mod;
    	NTT(f,-1);int ans=0;
    	rep(0,m,i)ans=(ans+(ll)w[i]*f[i+m]%mod*inv[i])%mod;
    	put((ans+mod)%mod);return 0;
    }
    
  • 相关阅读:
    Shell基础一
    Hash表
    哈希表
    设置不输入密码ssh登录
    C++ int与string的转化
    mysql之数据类型
    ICE之C/S通信原理
    mysql基础入门
    SQL练习之不反复执行相同的计算
    SQL练习之求解填字游戏
  • 原文地址:https://www.cnblogs.com/chdy/p/13068756.html
Copyright © 2011-2022 走看看