CF GYM100548 (相邻格子颜色不同的方案数 2014西安现场赛F题 容斥原理)

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 }
View Code

 

posted @ 2015-10-01 17:55  __Meng  阅读(716)  评论(0编辑  收藏  举报