• 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
    ",t,ans);
        }
    }
  • 相关阅读:
    JavaScript进阶-BOM和DOM
    JavaScript基础
    CSS2-属性
    CSS1-选择器
    HTML-常用标签
    判断回文
    课堂作业
    动手动脑
    原码反码补码
    Java第一次考试作业
  • 原文地址:https://www.cnblogs.com/csdeblog/p/8747047.html
Copyright © 2020-2023  润新知