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

    之前纠结了好久...

  • 相关阅读:
    500 多个 Linux 命令文档搜索
    C++ 字符串基本操作
    串的模式匹配算法
    查看、启动、关闭防火墙
    天润融通面试
    LeetCode 169. 求众数
    【面试题】人人车一次面试总结
    一个完整的 JS 身份证校验代码
    oracle多表查询
    百度地图的Icon
  • 原文地址:https://www.cnblogs.com/Recoder/p/5773486.html
Copyright © 2011-2022 走看看