[DP]HDU6415(2018多校訓練賽第九場 Problem A) Rikka with Nash Equilibrium 題解

_Wflower發表於2018-08-23

題目大意

給出一個 nm n ∗ m <script type="math/tex" id="MathJax-Element-3">n*m</script>的網格,現要在網格中填入1,2,……, nm n ∗ m <script type="math/tex" id="MathJax-Element-4">n*m</script>,如果一個格子數比同行同列的數都大,那麼就說這個格子佔領了這行這列,求只有一個格子佔滿一行一列的方案數。

解題報告

因為 nm n ∗ m <script type="math/tex" id="MathJax-Element-5">n*m</script>是最大的,所以他肯定佔領一行一列,所以這樣的話我們就必須保證其他的數都不能同時佔領一行一列了。

如果我們隨便把 nm n ∗ m <script type="math/tex" id="MathJax-Element-6">n*m</script>放在某個格子上,接下來放 nm1 n ∗ m − 1 <script type="math/tex" id="MathJax-Element-7">n*m-1</script>,那麼為了保證”其他數不能佔領“,那麼它只能放在 nm n ∗ m <script type="math/tex" id="MathJax-Element-8">n*m</script>所在行列上。再往下處理也是一樣,但是除了前面比它大的數所在行列之外,在交叉點上也可以放,同時被兩個大數壓制。

那麼就可以選擇從大到小放,根據前面的策略,發現要滿足題目限制,有三種可行的方案。

1.放在已覆蓋的一行上,只佔領一列。

2.放在已覆蓋的一列上,只佔領一行。

3.放在已覆蓋的一行一列交點處,沒有佔領。

考慮DP, f[i][j][k] f [ i ] [ j ] [ k ] <script type="math/tex" id="MathJax-Element-9">f[i][j][k]</script>表示已覆蓋 i i <script type="math/tex" id="MathJax-Element-10">i</script>行 j j <script type="math/tex" id="MathJax-Element-11">j</script>列,還有 k k <script type="math/tex" id="MathJax-Element-12">k</script>個已覆蓋的交點有空位的方案數,初始 f[1][1][0]=nm f [ 1 ] [ 1 ] [ 0 ] = n ∗ m <script type="math/tex" id="MathJax-Element-13">f[1][1][0]=n*m</script>, 答案就是 f[n][m][0] f [ n ] [ m ] [ 0 ] <script type="math/tex" id="MathJax-Element-14">f[n][m][0]</script>。

三種方案轉移一下……還是見程式碼吧。

示例程式碼

題目傳送門

#include<cstdio>
#define LL long long
using namespace std;
int tst,n,m,tt;
LL f[85][85][6405];
int main()
{
    freopen("nash.in","r",stdin);
    freopen("nash.out","w",stdout);
    scanf("%d",&tst);
    while (tst--){
        scanf("%d%d%d",&n,&m,&tt);
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++)
                for (int k=0;k<=i*j;k++) f[i][j][k]=0;
        f[1][1][0]=n*m;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++)
                for (int k=i*j;k>=0;k--)
                    if (f[i][j][k]){
                        if (i<n) f[i+1][j][k+j-1]=(f[i+1][j][k+j-1]+f[i][j][k]*((n-i)*j))%tt;
                        if (j<m) f[i][j+1][k+i-1]=(f[i][j+1][k+i-1]+f[i][j][k]*((m-j)*i))%tt;
                        if (k) f[i][j][k-1]=(f[i][j][k-1]+f[i][j][k]*k)%tt;
                    }
        printf("%lld\n",f[n][m][0]);
    }
    return 0;
}

相關文章