The 2014 ACM-ICPC Asia Xi’an Regional Contest Problem F. Color(二項式反演)

                                                 Problem F. Color

 

傳送門

題意:長度爲n的一個連續串讓你染色,使得相鄰位置的顏色不能一樣,且串中恰好一共出現k種顏色,問若是你有m種顏色(m>=k),一共有多少種染色方法滿足給定條件.

我們易推得如果僅僅是要求相鄰位置的顏色不一樣那麼

                                                                                ans=m*(m-1)^{n-1}

我們再次設對於恰好出現i種顏色的染色方法有G(i)種,那麼對於易得

                                                                           k*(k-1)^{n-1}=\sum\nolimits_{i=0}^k\binom{k}{i}*G(i)

我們再次設

                                                                                F(k)=k*(k-1)^{n-1}

那麼便可以得到這樣的一條等式

                                                                                F(k)=\sum\nolimits_{i=0}^k\binom{k}{i}*G(i)

對於形如上式的的式子,我們都可以得到以下反演結果

                                                                            G(k)=\sum\nolimits_{i=0}^k(-1)^{k-i}\binom{k}{i}*F(i)

以上都是二項式反演已知的固定反演形式,如果想要了解該等式的證明

可以參考lyf學長的證明

 

對於14年icpc西安區域賽的的這道題,若是已知這個結論這就是個秒A的水題了,然而今天打重現直接被這道題卡死了

問了問A了的隊友,說是感覺要容斥然後猜了一下結論就A了......

emmmm.......

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>
#include<set>
#include<queue>
#include<limits.h>
#include<string.h>
#include<map>
#include<list>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long long LL;

#define inf int(0x3f3f3f3f)
#define mod ll(1e9+7)
#define eps double(1e-6)
#define pi acos(-1.0)
#define lson  root << 1
#define rson  root << 1 | 1

ll n,m,k;

ll c[1000005];

ll inv[1000005];

ll powmod(ll a,ll b)
{
    ll ans=1;
    while(b)
    {
        if(b&1)
            ans=(ans*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }

    return ans;
}

void init()
{
    inv[0]=1;
    for(int i=1; i<=1000001; i++)
        inv[i]=powmod(i,mod-2);
}

void init_c()
{
    c[0]=1;
    for(int i=1; i<=k; i++)
        c[i]=c[i-1]*(k-i+1)%mod*inv[i]%mod;
}

ll C(ll n,ll m)
{
    ll ans=1;
    for(int i=1; i<=m; i++)
        ans=ans*(n-i+1)%mod*inv[i]%mod;
    return ans;
}



int main()
{
    init();
    cin.tie(0);
    cout.tie(0);
    int t;
    init();
    cin>>t;
    for(int i=1; i<=t; i++)
    {
        cin>>n>>m>>k;
        cout<<"Case #"<<i<<": ";
        init_c();
        ll ans=0;
        ll flag=-1;
        for(int i=k-1; i>=1; i--)
        {
            ans=(ans+flag*i*c[i]%mod*powmod(i-1,n-1)%mod+mod)%mod;
            flag*=-1;
        }
        ans=(ans+k*c[k]*powmod(k-1,n-1))%mod;
        ans=(ans*C(m,k)+mod)%mod;
        cout<<ans<<endl;
    }
}

 

發佈了86 篇原創文章 · 獲贊 3 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章