Gym - 100548F Color 组合数+容斥

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

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

题解:当我们用至少k中染色的时候 f[k] = k*(k-1)^(n-1)  其中包括了 至少k-1中的,我们需要减去C(k,k-1)*f[k-1]  ,但是很明显我们多减了一次至少f[k-2]次的,举个栗子:假设有1 2 3 4 5,我们先减去1 3 4 5 在减 2 3 4 5 所以其中多减了一次 3 4 5的 所以要再加上y一次f[k-2]  以此类推 ,这就是一个容斥,但是n,k,很大我们怎么办的,C(n,m+1)=C(n,m)*(n-m)/(m+1) 因此我们就需要求逆元了

注意乘法运算啊,每次乘,都要取模,否则就超1e9了 坑

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const int N=1e6+100;
const ll mod=1000000007;
ll C[N],inv[N],n,m,k;
ll ksm(ll a,ll b)
{
    ll ans=1;
    while(b)
    {
        if(b&1) ans=ans*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return ans;
}
void init()
{
    for(int i=1;i<N;i++)
        inv[i]=ksm(i,mod-2);
}
void cal(ll x)
{
    C[0]=1;
    for(int i=1;i<=k;i++)
        C[i]=((C[i-1]*(x-i+1)%mod)*inv[i]%mod)%mod;
}
int main()
{
    init();
    int T,nn=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld%lld",&n,&m,&k);
        cal(k);
        ll ans=k*ksm(k-1,n-1)%mod;
        for(ll i=2;i<=k-1;i++)
        {
            if((k-i)%2) ans=(ans-C[i]*(i*ksm(i-1,n-1)%mod)%mod)%mod;
            else ans=(ans+C[i]*(i*ksm(i-1,n-1)%mod)%mod)%mod;
        }
        cal(m);
        printf("Case #%d: %lld\n",nn++,(C[k]*ans%mod+mod)%mod);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/mmk27_word/article/details/83541095