swjtu2382(Paint Box)

来源:互联网 发布:宏业软件怎么用 编辑:程序博客网 时间:2024/06/16 07:29

题目链接:http://swjtuoj.cn/problem/2382/

容斥原理。首先,用k种颜色的方案为c(k,k)*(k)*(k-1)^(n-1),k种颜色方案中减去用k-1种颜色方案c(k,k-1)*(k-1)*(k-2)^(n-1),得到恰好用k种颜色方案数,多减去的k-2种颜色方案数c(k,k-2)*(k-2)*(k-3)^(n-1)要重新加上,依此类推。
ans = C(m,k)*Sigma(c(k,k-i)*(k-i)*(k-i-1)^(n-1)*(-1)^(i))(0<=i<k)。

知识点1:快速幂求乘法逆元
b 关于 mod 的逆元 x = b^(mod-2) % mod
(a / b) % mod = (a * x) % mod


知识点2:计算C(n,m)的快速计算方法

C(n,m) = (n*(n-1)*……*(n-m+1)) / m! = (n/1) * ((n-1)/2) * ((n-2) / 3) * …… * ((n-m+1) / 1)

除法用乘法逆元

具体见代码:

#include <iostream>#include <cstdio>#include <cmath>#include <map>using namespace std;typedef  long long ull;const ull mod = 1e9 + 7;ull ksp(ull a, ull b)//知识点1,快速幂求乘法逆元{    ull ret = 1;    while (b > 0)    {        if (b % 2 == 1)            ret = (ret * a) % mod;        b >>= 1;        a = (a * a) % mod;    }    return ret;}ull C(ull n, ull m)//知识点2{    ull ret = 1;    for (int i=1; i<=m; i++)    {        ret = ret * (n-i+1) % mod * ksp(i, mod-2) % mod;// (n-i+1)/i == (n-i+1)*(i 的逆元)    }    return ret;}int main(){    int t;    cin >> t;    for (int _=0; _<t; _++)    {        ull n, m, k;        scanf("%lld%lld%lld", &n, &m, &k);        ull ans = 0;        ull cmk = 1;        for (int i=1; i<=k; i++)        {            cmk = (((cmk * (k-i+1)) % mod) * ksp(i, mod-2)) % mod;            ull ret = (((cmk * i) % mod) * ksp(i-1, n-1)) % mod;            if ((k-i) % 2 == 1)                ans = (ans + mod - ret) % mod;            else                ans = (ans + ret) % mod;        }        ans = (ans * C(m,k)) % mod;        printf("%lld\n", ans);    }    return 0;}

原创粉丝点击