Gym 100548F Color 给花染色 容斥+组合数学+逆元 铜牌题

Problem F. Color
Description
Recently, Mr. Big recieved n flowers from his fans. He wants to recolor those flowers with
m colors. The flowers are put in a line. It is not allowed to color any adjacent flowers with
the same color. Flowers i and i + 1 are said to be adjacent for every i, 1 ≤ i < n. Mr. Big
also wants the total number of different colors of the n flowers being exactly k.
Two ways are considered different if and only if there is at least one flower being colored
with different colors.
Input
The first line of the input gives the number of test cases, T. T test cases follow. T is about
300 and in most cases k is relatively small.
For each test case, there will be one line, which contains three integers n, m, k (1 ≤ n, m ≤
109
, 1 ≤ k ≤ 106
, k ≤ n, m).
Output
For each test case, output one line containing “Case #x: y”, where x is the test case
number (starting from 1) and y is the number of ways of different coloring methods modulo
109 + 7.
Samples
Sample Input Sample Output
2
3 2 2
3 2 1
Case #1: 2
Case #2: 0

题意:给你N朵花,M种颜料(n,m<=1e9),要求给所有花染色,且相邻的花不能用同样的颜色,求出最后恰好用了k种

颜料的方案数(k<=1e5)

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#define MM(a,b) memset(a,b,sizeof(a));
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
#define CT continue
#define SC scanf
const int N=1e6+10;
const int mod=1e9+7;
int cas,n,m,k,kk;
ll C[N],inv[N];

ll _pow(ll a,ll b)
{
    ll res=1;
    while(b){
        if(b&1) res=(res*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return res;
}

void  init_yuan()
{
   inv[1]=1;
   for(int i=2;i<=1e6;i++){
       inv[i]=(mod-mod/i)*inv[mod%i]%mod;
   }
}//求逆元模板  

void init_cki()
{
    C[0]=1;
    for(int i=0;i<k;i++){
        C[i+1]=C[i]*(k-i)%mod*inv[i+1]%mod;
    }
}//预处理C(k,i)

ll c(ll m,ll k)
{
    ll res=1;
    k=min(k,m-k);
    for(int i=0;i<k;i++){
        res=res*(m-i)%mod;
    }
    for(int i=0;i<k;i++){
        res=res*inv[i+1]%mod;
    }
    return res;
}//求C(m,k)

int main()
{
    kk=0;
    init_yuan();
    SC("%d",&cas);
    while(cas--) {
        SC("%d%d%d",&n,&m,&k);
        init_cki();
        ll ans=k*_pow(k-1,n-1)%mod,res=0;
        for(int i=1;i<=k-2;i++) {
            if(i%2) res+=C[i]*(k-i)%mod*_pow(k-i-1,n-1)%mod;
            else res=(res-C[i]*(k-i)%mod*_pow(k-i-1,n-1)+mod)%mod;
        }
        ans=(ans-res+mod)%mod;
        ans=(ans*c(m,k))%mod;
        printf("Case #%d: %lld
",++kk,ans);
    }
    return 0;
}

  错因分析:刚开始想的是直接在n上容斥,,果然是太过复杂,,,就挂了;;

解答:1.可以转换下思路,,如果当前选了k种,那么涂完后花的颜色不超过k种的方案数为S=k*_pow(k-1,n-1),想象其是一个集合,设a[i](1<=i<=k)代表第i种颜料并没有用到,那么那么此情况下答案就为S-(a[1]并a[2]并...a[k])的面积,但是后面这个部分肯定是a[1]和a[2]等这些存在交集,所以就需要容斥了,最后因为存在C(m,k)种情况所以答案出来后还要乘C(m,k)

2.除法取模需要用到逆元见资料

原文地址:https://www.cnblogs.com/smilesundream/p/5840630.html