codeforces gym 100548f

Posted 称雄

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了codeforces gym 100548f相关的知识,希望对你有一定的参考价值。

题目如图

题意是说给n个花,m种颜色,要求相邻花颜色不能相同,总共有k种不同的颜色。

  刚开始想的是从m种颜色里选k种,然后第一朵花有k种选法,后面的都是k-1种,这样就是C(m,k) * (k - 1) ^ (n - 1) * k,然后交的时候第二个一直wa,后来发现会这样并不能保证有k种颜色,比如4朵花3种颜色可以是1,2,1,2,只有两种颜色。所以后来的思路是从这个里面减去不超过k - 1种颜色的选法就是答案,然后想的式子是C(m,k)((k - 1) ^ (n - 1) * k - C(k,k - 1) * (k - 1) * (k - 2) ^ (n - 1)),这个意思是k种颜色里选k - 1种涂n朵花,第一朵是k - 1种涂法,后面都是k - 2种,所以就是 C(k,k - 1) * (k - 1) * (k - 2) ^ (n - 1),减去这种情况就是k种颜色的,后来发现这样也有问题。比如n = 4,m = 4,k = 4的时候,假设颜色是从1到4,从k = 4种颜色里选三种颜色会有1,2,3  , 1,2,4,  1,3,4  ,2,3,4这四种选法,其中在1,2,3这种情况会有1,2,1,2这种涂法,在1,2,4这种情况也会有1,2,1,2这种涂法,相当于把两种颜色的算了两遍。然后依次类推从五种颜色选四种会出现把三种颜色的算2遍,两种颜色的算三遍。记f[i] =  C(k,i) * i * (i - 1) ^ (n - 1),那么不超过2种颜色的应该是f[2] - f[1],不超过三种颜色是f[3] - 不超过两种的,不超过四种是f[4] - 不超过三种的,所以不超过k - 1种就是f[k - 1] - 不超过k - 2种的,可以列出式子为(f[k - 1] - (f[k - 2] - (f[k - 3]… - (f[2] - f[1])))),然后由(k - 1) ^ (n - 1) * k减去它,也就是这种形式C(m,k) * (∑(i = 2,k) (-1) ^ (k - i) * f[i])。

  在算的过程中需要用到逆元,因为求C(n,m)需要用到除法,所以用快速幂处理,a的逆元就是pow(a,mod - 2)。然后要对C(k,i)进行打表,求出i从1到k的值,还需要在最外层对逆元从1到1000000打表,不然会超时。

代码如下:

#include<stdio.h> 
#include<math.h>
#include<set>
using namespace std;
typedef long long ll;
const int mod = 1000000007;
ll c[1000010],inverse[1000010];
ll quickPow(ll a,ll n){
    if(n == 0)
        return 1;
    ll ans = quickPow(a,n / 2);
    ans=ans%mod;
    if(n % 2 == 0)
        return ans * ans % mod;
    return (((ans * ans) % mod) * a) % mod;
}

ll C(ll a,ll b){
    ll ans=1;
    for(int i=1;i<=b;i++){
        ans*=(a-i+1);
        ans%=mod;
        ans*=inverse[i];
        ans%=mod;
    }
    return ans;
}
int main(){
    int T;
    scanf("%d",&T);
    int t = 0;
    for(int i = 1;i <= 1000000;i++)
        inverse[i] = quickPow(i,mod - 2);
    while(T--){
        t++;
        ll n,m,k;
        scanf("%lld%lld%lld",&n,&m,&k);
        c[1] = k;
        for(int i = 2;i <= k;i++){
            c[i] = c[i - 1] * (k - i + 1) % mod;
            c[i] = c[i] * inverse[i] % mod;
        }
        ll ans = 0;
        int sign = pow(-1,k - 1);
        for(int i = 1;i <= k;i++){
            ans = (ans + sign * i % mod * c[i] % mod * quickPow(i - 1, n - 1) % mod + mod) % mod;
            sign *= -1;
        }
        ans = ans * C(m,k) % mod;
        printf("Case #%d: %lld\\n",t,ans);
    }
}

 

以上是关于codeforces gym 100548f的主要内容,如果未能解决你的问题,请参考以下文章

CodeForces Gym 100685I Innovative Business (贪心)

codeforces gym #101161G - Binary Strings(矩阵快速幂)

codeforces Gym 100971 ABCFGKL

codeforce Gym 101102A Coins (01背包变形)

Codeforces Gym 100342J Problem J. Triatrip 三元环

CodeForces Gym 100685C Cinderella (水题)