题目大意:
用k种颜色涂 n*m 的矩形,要求 如果 1~i 和 i+1~m 所用的颜色种类一样多,不要求颜色一样、
思路:
可以推出 第一列和第m列所用的颜色数量是一样的。
证明 :如果a[1~1]=i a[m~m]=j (i<j)
那么a[1~1]=i<j<=a[2~m] 所以不满足
然后中间的m-2列 是不能出现新颜色的。也就是必须是第一列和第m列的颜色不然会导致两边不相等了。
用dp[i] 表示用i种颜色且必须是i种颜色涂在n个格子上的方式。
那么 dp[i] = i^n-segma(C(i,j)*dp[j]) 1<=j<i 也就是减去只涂了少于i种的情况
然后我们开始处理,
当m==1的时候 就是k^n
当m==2的时候 左边i种 右边 i种 就是 (C(k,i)*dp[i])^2...
当m==3的时候
要枚举相同的颜色的数量i 和不同的颜色的数量j
第一列在k个里选i个 然后在k-i个里选择选择j个 第m列则要在k-i-j里再选j个
然后再涂上去 就是乘以 dp[i+j]...
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> typedef long long LL; using namespace std; const LL mod=1000000007; LL fac[1000005]={1},rev[1000005]={1}; LL dp[1005]; LL pow_mod(LL a,LL i,LL n) { if(i==0)return 1%n; LL temp=pow_mod(a,i>>1,n); temp=temp*temp%n; if(i&1)temp=temp*a%n; return temp; } void init() { for(int i=1;i<=1000000;i++) fac[i]=fac[i-1]*i%mod,rev[i]=pow_mod(fac[i],mod-2,mod); } LL C(int n,int m) { return (fac[n]*rev[m]%mod)*rev[n-m]%mod; } int main() { init(); int n,m,k; scanf("%d%d%d",&n,&m,&k); if(m==1) { printf("%I64d\n",pow_mod(k,n,mod)); return 0; } for(int i=1;i<=n && i<=k;i++) { dp[i]=pow_mod(i,n,mod); for(int j=1;j<i;j++) { dp[i]=(dp[i]-C(i,j)*dp[j]%mod)+mod; dp[i]%=mod; } } LL ans=0; if(m==2) { for(int i=1;i<=n && i<=k;i++) { ans=(ans+(((dp[i]*dp[i]%mod)*C(k,i)%mod)*C(k,i))%mod)%mod; } printf("%I64d\n",ans); } else { for(int i=1;i<=n && i<=k;i++) { for(int j=0;2*j+i<=k && i+j<=n;j++) { LL tmp=dp[i+j]*dp[i+j]%mod; tmp=((tmp*C(k,i)%mod)*C(k-i,j)%mod)*C(k-i-j,j)%mod; tmp=(tmp*pow_mod(i,n*(m-2),mod))%mod; ans=(ans+tmp)%mod; } } printf("%I64d\n",ans); } return 0; }
CF 111D - Petya and Coloring,布布扣,bubuko.com
原文:http://blog.csdn.net/u010709592/article/details/21131863