zoukankan      html  css  js  c++  java
  • Codeforces 100548F

    题目链接:http://codeforces.com/gym/100548/attachments

    有n个物品 m种颜色,要求你只用k种颜色,且相邻物品的颜色不能相同,问你有多少种方案。

    从m种颜色选k种颜色有C(m, k)种方案,对于k种颜色方案为k*(k-1)^(n-1)种。但是C(m, k)*k*(k-1)^(n-1)方案包括了选k-1,k-2...,2种方案。

    题目要求刚好k种颜色,所以这里想到用容斥。

    但是要是直接C(m, k)*k*(k-1)^(n-1) - C(m, k-1)*(k-1)*(k-2)^(n-1)的话,其实是多减的。

    比如k=4,4种颜色1 2 3 4,有种染色方案是1 2 1 2,那么k-1的话1 2 3或者1 2 4也有染色方案是1 2 1 2,这里发现多减了。所以k-2还得加上。

    所以公式就变成了

    C(m, k)*( k*(k-1)^(n-1) - C(k, k-1)*(k-1)*(k-2)^(n-1) + C(k, k-2)*(k-2)*(k-3)^(n-1) ... )

    中间的组合数C(k, i),可以用逆元来解决。C(m, k)则暴力即可。

     1 //#pragma comment(linker, "/STACK:102400000, 102400000")
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <cstdlib>
     5 #include <cstring>
     6 #include <cstdio>
     7 #include <vector>
     8 #include <cmath>
     9 #include <ctime>
    10 #include <list>
    11 #include <set>
    12 #include <map>
    13 using namespace std;
    14 typedef __int64 LL;
    15 typedef pair <int, int> P;
    16 const int N = 1e6+ 5;
    17 LL mod = 1e9 + 7;
    18 LL f[N];
    19 
    20 LL Pow(LL a , LL n , LL mod) {
    21     LL res = 1;
    22     while(n) {
    23         if(n & 1)
    24             res = res * a % mod;
    25         a = a * a % mod;
    26         n >>= 1;
    27     }
    28     return res;
    29 }
    30 
    31 LL Cnm(LL n, LL m, LL mod) {
    32     if(n < N) { //数据范围小的 逆元就好了
    33         return f[n]*Pow(f[m]*f[n-m]%mod, mod - 2, mod) % mod;
    34     }
    35     LL res = Pow(f[m]%mod, mod - 2, mod)%mod;
    36     for(LL i = 0; i < m; ++i) { 
    37         res = res * (n-i) % mod;
    38     }
    39     return res%mod;
    40 }
    41 
    42 void init() { //阶乘预处理
    43     f[0] = 1;
    44     for(LL i = 1; i < N; ++i)
    45         f[i] = f[i - 1] * i % mod;
    46 }
    47 
    48 int main()
    49 {
    50     init();
    51     int t;
    52     LL n, m, k;
    53     scanf("%d", &t);
    54     for(int ca = 1; ca <= t; ++ca) {
    55         scanf("%lld %lld %lld", &n, &m, &k);
    56         printf("Case #%d: ", ca);
    57         if(k == 1 && n == 1) {
    58             printf("%lld
    ", m);
    59             continue;
    60         }
    61         else if(k == 1) {
    62             printf("0
    ");
    63             continue;
    64         }
    65         LL ans = 0, temp = k;
    66         for(int i = 1; k >= 2; --k, i = -i) {
    67             ans = (i * Cnm(temp, k, mod) % mod *k % mod* Pow(k- 1, n - 1, mod) % mod + ans) % mod;
    68         }
    69         ans = ans * Cnm(m, temp, mod) % mod;
    70         printf("%lld
    ", (ans + mod) % mod);
    71     }
    72     return 0;
    73 }
    View Code

    之前纠结了好久...

  • 相关阅读:
    垂死挣扎还是涅槃重生 -- Delphi XE5 公布会归来感想
    自考感悟,话谈备忘录模式
    [每日一题] OCP1z0-047 :2013-07-26 alter table set unused之后各种情况处理
    Java实现 蓝桥杯 算法提高 p1001
    Java实现 蓝桥杯 算法提高 拿糖果
    Java实现 蓝桥杯 算法提高 拿糖果
    Java实现 蓝桥杯 算法提高 求arccos值
    Java实现 蓝桥杯 算法提高 求arccos值
    Java实现 蓝桥杯 算法提高 因式分解
    Java实现 蓝桥杯 算法提高 因式分解
  • 原文地址:https://www.cnblogs.com/Recoder/p/5773486.html
Copyright © 2011-2022 走看看