UVALive 7040 Color

题目链接:LA-7040

题意为用m种颜色给n个格子染色。问正好使用k种颜色的方案有多少。

首先很容易想到的是\( k * (k-1)^{n-1}\),这个算出来的是使用小于等于k种颜色给n个方格染色的方案数。

我们希望求得的是使用正好k种颜色给n个方格染色的方案数,简单的想法是,直接减去小于等于k-1种颜色的方案数。

但是,要计算使用小于等于k-1种颜色染色的方案数,不能直接减去\(C_{k}^{k-1} * (k-1) * (k-2)^{n-1}\),原因是会有重复的部分。

我们用\(S_{k}\)表示使用小于等于k种颜色给n个格子染色的方案数。

则我们希望求出的答案可以用\(C_m^k * (S_k- \bigcup _{i=1} ^ {C_k^{k-1}} S_{k-1})\)来表示。

于是问题变成了求\( \bigcup _{i=1} ^ {C_k^{k-1}} S_{k-1}\),因为有重复,自然而然的我们想到容斥原理。

仔细思考后(或者列表格),发现所有\(S_{k-1}\)两两相交的并等于\(S_{k-2}\),所有\(S_{k-1}\)三三相交的并等于\(S_{k-3}\),以此类推,减加减加即可。

 

代码如下:

 1 #include<cstring>
 2 #include<cstdio>
 3 #include<queue>
 4 #include<algorithm>
 5 #include<set>
 6 #include<cmath>
 7 using namespace std;
 8 typedef long long LL;
 9 const LL MAXK=1000000;
10 const LL MOD=1e9+7;
11 
12 LL CM[MAXK+10],CK[MAXK+10],inv[MAXK+10];
13 LL extgcd(LL a,LL b,LL &x,LL &y)
14 {
15     LL d=a;
16     if(b!=0)
17     {
18         d=extgcd(b,a%b,y,x);
19         y-=(a/b)*x;
20     }
21     else { x=1; y=0; }
22     return d;
23 }
24 //快速幂
25 //求x^n%mod
26 LL powMod(LL x,LL n,LL mod)
27 {
28     LL res=1;
29     while(n>0)
30     {
31         if(n&1) res=res*x % mod;
32         x=x*x % mod;
33         n>>=1;
34     }
35     return res;
36 }
37 //求逆元
38 //a和m应该互质
39 LL modInverse(LL a,LL m)
40 {
41     LL x,y;
42     extgcd(a,m,x,y);
43     return (m+x%m)%m;
44 }
45 LL n,m,k;
46 void init()
47 {
48     CM[0]=1;
49     for(LL i=0;i<=k-1;i++)
50         CM[i+1]=CM[i]*(m-i) %MOD *inv[i+1] % MOD;
51     CK[0]=1;
52     for(LL i=0;i<=k-1;i++)
53         CK[i+1]=CK[i]*(k-i) %MOD *inv[i+1] % MOD;
54 }
55 LL f(LL n,LL k)
56 {
57     LL ans = 0;
58     LL flag=1;
59     for(LL i=k;i>=1;i--)
60     {
61         ans = (flag * CK[i] % MOD * i % MOD * powMod(i-1,n-1,MOD) % MOD +ans + MOD ) % MOD;
62         flag*=-1;
63     }
64     ans = ans*CM[k]%MOD;
65     return ans;
66 }
67 int main()
68 {
69 #ifdef LOCAL
70     freopen("in.txt","r",stdin);
71     // freopen("out.txt","w",stdout);
72 #endif
73     for(LL i=1;i<=MAXK;i++) inv[i]=modInverse(i,MOD);
74     LL t;
75     scanf("%lld",&t);
76     for(LL tt=1;tt<=t;tt++)
77     {
78         scanf("%lld%lld%lld",&n,&m,&k);
79         init();
80         printf("Case #%lld: %lld\n",tt,f(n,k)%MOD);
81     }
82     return 0;
83 }

 

posted @ 2017-03-26 17:37  HuaZhang  阅读(353)  评论(0编辑  收藏  举报