zoukankan      html  css  js  c++  java
  • 【弱省胡策】Round #5 Count

    【弱省胡策】Round #5 Count

    img

    太神仙了。

    (DP)做法

    (f_{n,m,d,k})表示(n*m)的矩阵,填入第(k)个颜色,并且第(k)个颜色最少的一列上有(d)个块染了(k)颜色。

    [displaystyle f_{n,m,d,k}=sum_{i=1}^nC_n^icdot (C_m^d)^icdot f_{i,m-d,0,k-1}cdot f_{n-i,m,d+1,k} ]

    边界条件特别烦,当(n=1)或者(n==1&&m==0)(f)的值为(1)

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define N 25
    #define M 55
    
    using namespace std;
    inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
    
    const ll mod=1e9+7;
    int n,m,k;
    ll f[N][M][M][105];
    ll C[M][M];
    
    ll ksm(ll t,ll x) {
    	ll ans=1;
    	for(;x;x>>=1,t=t*t%mod)
    		if(x&1) ans=ans*t%mod;
    	return ans;
    }
    
    int main() {
    	for(int i=0;i<=50;i++)
    		for(int j=0;j<=i;j++)
    			C[i][j]=(!j||i==j)?1:(C[i-1][j-1]+C[i-1][j])%mod;
    	n=Get(),m=Get(),k=Get();
    	
    	memset(f,0,sizeof(f));
    	for(int i=0;i<=n;i++)
    		for(int j=0;j<=m;j++)
    			for(int d=0;d<=m+1;d++)
    				for(int c=0;c<=k;c++)
    					if(!i||(i==1&&j==0)) 
    						f[i][j][d][c]=1;
    					
    	
    	for(int c=1;c<=k;c++) {
    		for(int i=1;i<=n;i++) {
    			for(int j=1;j<=m;j++) {
    				for(int d=j;d>=0;d--) {
    					for(int q=1;q<=i;q++) {
    						(f[i][j][d][c]+=C[i][q]*ksm(C[j][d],q)%mod*f[q][j-d][0][c-1]%mod*f[i-q][j][d+1][c])%=mod;
    					}
    					(f[i][j][d][c]+=f[i][j][d+1][c])%=mod;
    				}
    			}
    		}
    	}
    	cout<<f[n][m][0][k];
    	return 0;
    }
    
    

    容斥做法

    参考Luogu P4463的容斥做法。

    我们先定义两行同构为:这两行中每种颜色出现次数相同。

    我们设(f_n)表示(n)(m)列且任意两行不同构的方案数。设(s_i)表示有(i)行矩形同构的方案数。

    然后我们考虑加入第(n+1)行。我们枚举至少有(i)行与第(n+1)行同构的方案数为(g_i),则:

    [g_i=s_icdot f_{n-i} ]

    我们设恰好有(i)行与第(n+1)行矩形同构的方案数为(h_i),则:

    [g_i=h_i+inom{i+1}{i}h_{i+1} ]

    因为剩下的(n-i)行两两不同构,所以最多有(i+1)行与第(n+1)行同构。

    (g_i)的容斥系数为(c_i)。考虑(h_i)被计算的次数为(c_i+inom {i}{i-1}c_{i-1}),所以

    [c_i+inom {i}{i-1}c_{i-1}=[i==0] ]

    因为(c_0=0),所以我们就可以解出(c_i=(-1)^i i!)

    关于计算(s_i)

    [s_i=(frac{m!}{prod num_k!})^i ]

    其中(num_k)表示第(k)种颜色出现的次数。

    这个其实就可以枚举(i)之后做背包,然后显然可以用(NTT)优化,于是数据范围可以扩大。

    (懒得写(MTT)就改了模数)

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define N 205
    #define M 205
    
    using namespace std;
    inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
    
    const ll mod=998244353;
    int n,m,k;
    ll fac[M],ifac[M];
    
    ll ksm(ll t,ll x) {
    	ll ans=1;
    	for(;x;x>>=1,t=t*t%mod)
    		if(x&1) ans=ans*t%mod;
    	return ans;
    }
    ll f[N],g[N];
    ll C(int n,int m) {return fac[n]*ifac[m]%mod*ifac[n-m]%mod;}
    
    ll NTT(ll *a,int d,int flag) {
    	static ll G=3;
    	static int rev[M<<2];
    	int n=1<<d;
    	for(int i=0;i<n;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<d-1);
    	for(int i=0;i<n;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
    	for(int s=1;s<=d;s++) {
    		int len=1<<s,mid=len>>1;
    		ll w=flag==1?ksm(G,(mod-1)/len):ksm(G,mod-1-(mod-1)/len);
    		for(int i=0;i<n;i+=len) {
    			ll t=1;
    			for(int j=0;j<mid;j++,t=t*w%mod) {
    				ll u=a[i+j],v=a[i+j+mid]*t%mod;
    				a[i+j]=(u+v)%mod;
    				a[i+j+mid]=(u-v+mod)%mod;
    			}
    		}
    	}
    	if(flag==-1) {
    		ll inv=ksm(n,mod-2);
    		for(int i=0;i<n;i++) a[i]=a[i]*inv%mod;
    	}
    }
    
    void pre(int n) {
    	fac[0]=1;
    	for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod;
    	ifac[n]=ksm(fac[n],mod-2);
    	for(int i=n-1;i>=0;i--) ifac[i]=ifac[i+1]*(i+1)%mod;
    }
    
    ll A[M<<2],ans[M<<2];
    ll s[N][M];
    
    void ksm(ll *A,ll *ans,int d,int x) {
    	memset(ans,0,sizeof(ans));
    	ans[0]=1;
    	for(;x;x>>=1) {
    		if(x&1) {
    			NTT(ans,d,1),NTT(A,d,1);
    			for(int i=0;i<1<<d;i++) ans[i]=ans[i]*A[i]%mod;
    			NTT(ans,d,-1),NTT(A,d,-1);
    			for(int i=1<<d-1;i<1<<d;i++) ans[i]=0;
    		}
    		NTT(A,d,1);
    		for(int i=0;i<1<<d;i++) A[i]=A[i]*A[i]%mod;
    		NTT(A,d,-1);
    		for(int i=1<<d-1;i<1<<d;i++) A[i]=0;
    	}
    }
    
    ll S[N];
    
    int main() {
    	n=Get(),m=Get(),k=Get();
    	pre(N-5);
    	int len=m*k;
    	int d=ceil(log2(m<<1|1));
    	for(int i=1;i<=n;i++) {
    		memset(A,0,sizeof(A));
    		for(int j=0;j<=m;j++) {
    			A[j]=ksm(ifac[j],i);
    		}
    		memset(ans,0,sizeof(ans));
    		ksm(A,ans,d,k);
    		S[i]=ans[m]*ksm(fac[m],i)%mod;
    	}
    	
    	f[0]=1;
    	for(int i=1;i<=n;i++) {
    		for(int j=0;j<i;j++) {
    			g[j]=C(i-1,j)*f[i-j-1]%mod*S[j+1]%mod;
    		}
    		for(int j=i-1;j>=0;j--) g[j]=(g[j]-g[j+1]*(j+1)%mod+mod)%mod;
    		f[i]=g[0];
    	}
    	cout<<f[n];
    	
    	return 0;
    }
    
    
  • 相关阅读:
    TDSCDMA手机(WM系统)信号的采集?
    vc2008 + libpq + postgresql 8.4 配置
    code complete 2阅读笔记(第二章)
    Python 学习笔记(一)语句,变量,函数
    CS通用模型设计,socket,tcp实现()
    VS2005,VS2008编辑器设置
    设计模式之个人理解单例模式
    请教:C#网络编程相关的知识,建立socket服务器时向客户端连接,就建立不了了?
    服务器开发
    年终总结
  • 原文地址:https://www.cnblogs.com/hchhch233/p/10473648.html
Copyright © 2011-2022 走看看