Problem H. Great Cells(2016 China-Final)【數學計數+智力題】

source:題目鏈接

題意:這是2016 ACM-ICPC China-Final的H題,在N×M的網格里填[1,K]的整數,定義一個格子是great的,如果滿足這個格子中的數是本行和本列中嚴格的最大值。定義A-g爲網格中恰好有g個great格子的填法數,求Σ(g+1)A-g

思路:這題乍一看需要用組合數學 容斥原理計算A-g,但是這樣做比較麻煩複雜。但其實這題是(g+1)的套路。。。簡便做法是觀察整體,把問題轉化成每個位置是great格子對最終答案的貢獻和,這樣就繞開了A-g的計算。

首先,考慮整體的填法:K^(M×N)——這個是容易計算的,那麼我們先企圖用整體填法數化簡待求式!我們發現將待求式展開,後面的ΣA-g的和便是整體的填法數。(一般都需要先拿整體化簡一把!)

於是現在只需着手計算Σg*A-g,這個就用貢獻和的思想轉化,因爲有g個great格的填法數乘了個g相當於攤到了這g個位置上,也就是說每個great格獨立了,也即每一個格是great格對Σg*A-g貢獻=使這個格是great的所有填法總數:

Contrib=Σ(i=1到i=K-1)i^(N-1+M-1)×K^[(N-1)×(M-1)]       (轉化爲貢獻和,有點智力題的感覺orz..)

這裏注意一點:以上公式沒有考慮n=m=1的情況,因爲這時填1也算是great格(而以上公式從填2開始考慮的)

從而最後

ans=Contrib×N×M+K^(M×N)


代碼如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL mod=1e9+7;

LL qmod(LL a,LL b)  //快速冪
{
    LL ans=1;
    while(b)
    {
        if(b&1==1) ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}

int main()
{
    int t,T;
    LL m,n,k,ans;
    scanf("%d",&T);
    for(t=1;t<=T;t++)
    {
        scanf("%lld%lld%lld",&n,&m,&k);
        ans=0;
        for(LL i=1;i<k;i++)
        {
            ans=(ans+qmod(i,m+n-2))%mod;
        }
        ans=ans*qmod(k,(m-1)*(n-1))%mod;
        ans=(ans*n%mod)*m%mod;
        ans=(ans+qmod(k,n*m))%mod;
        if(m==1 && n==1) ans=(ans+1)%mod; //m=n=1時特判!!!
        printf("Case #%d: %lld\n",t,ans);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章