description:
一個矩陣有N行M列,現有k種顏色,求符合下列要求的填色方案有多少種
要求:將矩陣豎直的切分紅非空的兩部分,兩部分所包含的顏色數相同(只是顏色數相同,並無要求是有相同的顏色)ide
solution:
考慮每種合法的填色方案
假設最左邊一列的顏色種類爲 a ,則剩餘的部分也只能有k種顏色
此時左邊的兩列的顏色數一定不小於 a(多了一列),除去左邊兩列所剩的矩陣的顏色數一定不超過 a(少了一列)
又由於這個矩陣符合要求,故左邊兩列的顏色 = 除去左邊兩列的 = a
也就說明左邊的第二列的顏色一定在左邊第一列出現過
如此重複下去,能夠證實,除了左邊第一列和右邊第一列,矩陣剩餘部分的顏色一定都在左邊第一列(右邊第一列)出現過
不妨設左邊第一列和右邊第一列公共的顏色數爲 b ,顯然矩陣剩餘部分的顏色數不超過 b ,因而中間那部分的填色方案確定爲 b ^ (n (m - 2))
如今要去算左邊第一列和右邊第一列的填色方案,顯然這兩個都是相等的,因此如今就是考慮一個1*n的數組用正好a種顏色填充的方案數
這個就是容斥原理就能夠知道,設方案數爲 F(a, n) = a ^ n - C(a, 1) * (a - 1) ^ n + C(a, 2) * (a - 2) ^ n - ...
因而總方案數爲 ∑ C(k, a) * C(a, b) * C(k - a, a - b) F(a, n) ^ 2 * b ^ (n (m - 2))ui
hint:
注意考慮a和b的枚舉範圍 //我就是在這裏WA了好久……
注意取模 //如今弱爆了,這個都寫錯
m = 1 也要考慮spa
code:code
1 #include<bits/stdc++.h> 2 using namespace std; 3 char ch; bool ok; 4 void read(int &x){ 5 for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1; 6 for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar()); 7 if (ok) x=-x; 8 } 9 const int maxk=1000005; 10 const int mod=1E9+7; 11 int fac[maxk],inv[maxk],invfac[maxk]; 12 int n,m,k; 13 int ksm(int a,int b){ 14 int t; 15 for (t=1;b;b>>=1,a=1LL*a*a%mod) if (b&1) t=1LL*t*a%mod; 16 return t; 17 } 18 int C(int n,int m){ 19 int res=1LL*fac[n]*invfac[m]%mod*invfac[n-m]%mod; 20 return res; 21 } 22 int main(){ 23 read(n),read(m),read(k); 24 int lim=max(n,k); 25 fac[0]=1; 26 for (int i=1;i<=lim;i++) fac[i]=1LL*fac[i-1]*i%mod; 27 inv[1]=1; 28 for (int i=2;i<=lim;i++) inv[i]=1LL*(mod-mod/i)*inv[mod%i]%mod; 29 invfac[0]=1; 30 for (int i=1;i<=lim;i++) invfac[i]=1LL*invfac[i-1]*inv[i]%mod; 31 int ans=0; 32 if (m==1){ 33 printf("%d\n",ksm(k,n)); 34 return 0; 35 } 36 for (int a=1;a<=min(n,k);a++){ 37 int res=0; 38 for (int i=0;i<a;i++){ 39 int tmp=1LL*C(a,i)*ksm(a-i,n)%mod; 40 if (i&1) tmp=mod-tmp; 41 res=(res+tmp)%mod; 42 } 43 res=1LL*res*res%mod; 44 res=1LL*res*C(k,a)%mod; 45 for (int b=max(2*a-k,0);b<=a;b++){ 46 ans=(ans+1LL*res*C(a,b)%mod*C(k-a,a-b)%mod*ksm(b,n*(m-2))%mod)%mod; 47 } 48 } 49 printf("%d\n",ans); 50 return 0; 51 }