n个格子排成一行,有m种颜色,问用恰好k种颜色进行染色,使得相邻格子颜色不同的方案数。
integers n, m, k (1 ≤n, m ≤ 10^9, 1 ≤ k ≤ 10^6, k ≤ n, m).
m种颜色取k种 C(m, k) 这个可以放最后乘 那么问题就变成只用k种颜色
第一个格子有k种涂法 第二个有k-1种 第三个也是k-1种
一共就是k*(k-1)^(n-1) 这种算法仅保证了相邻颜色不同,总颜色数不超过k种,并没有保证恰好出现k种颜色 也就是多算了恰好出现2种 恰好出现3种.... 恰好出现k-1种
我们本来是要求 恰好用k的种 现在又要求恰好出现k-1种
那么就是 (k-1)*(k-2)^(n-1) 然后这个也是多算了一些情况的
以此类推 然后就可以用容斥原理
比如有5种颜色,选4种 就是
C(5, 4) * (C(4, 4)*4*3^4 - C(4, 3)*3*2^4 + C(4, 2)*2*1^4)
Sample Input
2
3 2 2// n m k
3 2 1
Sample Output
Case #1: 2
Case #2: 0
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 # include <algorithm> 5 # include <string> 6 # include <cmath> 7 # include <queue> 8 # include <list> 9 # define LL long long 10 using namespace std ; 11 12 const int MOD = 1000000007 ; 13 14 int n , m , k ; 15 LL CM ; 16 LL CK[1000010] ; 17 LL INV[1000010] ; 18 19 20 LL pow_mod(LL p, LL k) 21 { 22 LL ans = 1; 23 while(k) { 24 if (k & 1) ans = ans * p % MOD; 25 p = (LL)p*p % MOD; 26 k >>= 1; 27 } 28 return ans; 29 } 30 31 LL Ext_gcd(LL a,LL b,LL &x,LL &y){ //扩展欧几里德 32 if(a==0&&b==0) return -1; 33 if(b==0) { x=1, y=0; return a; } 34 LL d= Ext_gcd(b,a%b,y,x); 35 y-= a/b*x; 36 return d; 37 } 38 //ax = 1(mod m) 39 LL Inv(LL a,LL m){ //求逆元 a对m的逆元 40 LL d,x,y,t = m; 41 d= Ext_gcd(a,t,x,y); 42 if(d==1) return (x%t+t)%t; 43 return -1; 44 } 45 46 47 LL Cm(LL n, LL m, LL p) //求组合数 48 { 49 LL a=1, b=1; 50 if(m>n) return 0; 51 while(m) 52 { 53 a=(a*n)%p; 54 b=(b*m)%p; 55 m--; 56 n--; 57 } 58 return (LL)a*Inv(b,p)%p; //(a/b)%p 等价于 a*(b,p)的逆元 59 } 60 61 int Lucas(LL n, LL m, LL p) //把n分段递归求解相乘 62 { 63 if(m==0) return 1; 64 return (LL)Cm(n%p,m%p,p)*(LL)Lucas(n/p,m/p,p)%p; 65 } 66 67 void init() 68 { 69 INV[1] = 1 ; 70 int i ; 71 for (i = 2 ; i < 1000010 ; i++) 72 INV[i] = Inv(i,MOD) ; 73 } 74 75 int main() 76 { 77 //freopen("in.txt","r",stdin) ; 78 int T ; 79 scanf("%d" , &T) ; 80 int Case = 0 ; 81 init() ; 82 while(T--) 83 { 84 Case++ ; 85 scanf("%d%d%d" , &n , &m , &k) ; 86 if (n == 1) 87 { 88 printf("Case #%d: %d\n", Case , m); 89 continue ; 90 } 91 int i ; 92 CM = Cm(m,k,MOD) ; 93 CK[0] = 1 ; 94 for (i = 1 ; i <= k ; i++) 95 CK[i] = (CK[i-1] * (k-i+1)%MOD * INV[i])%MOD ; 96 LL ans = 0 , t = 1 ; 97 for (i = k ; i >= 2 ; i--) 98 { 99 ans = (ans + t*CK[i]*i%MOD*pow_mod(i-1,n-1)%MOD+MOD)%MOD ; 100 t *= -1 ; 101 } 102 printf("Case #%d: %I64d\n",Case,ans*CM%MOD); 103 104 } 105 return 0; 106 }
时间: 2024-10-05 13:17:45