HDU多校第九次 6415 (dp

城南的花發表於2018-08-21

dp是不可能的,這輩子都寫不出的。。。

當放最大數字的時候只能佔據一行一列
其餘的數字
1. 只佔據1行
2. 只佔據1列
3. 填充在被佔據過的行和列裡面

這裡需要對取模優化
有兩種方法吧
1. 減少取模次數
2. 結果值改成int,每次都存到int裡面

void update(int &k1,long long k2){//後面的數字用來儲存可能爆int的乘法
    k1=(k1+k2)%mo;
}

增加新的點不增加行列:放在交點

#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll dp[6455][85][85]; //dp[i][j][k]:有i個點,佔據了j行k列有幾種放法
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,m,mod;
        scanf("%d%d%d",&n,&m,&mod);
        memset(dp,0,sizeof(dp));
        dp[1][1][1]=n*m;
        for(int i=1;i<n*m;i++)
        {
            for(int j=1;j<=n;j++)
            {
                for(int k=1;k<=m;k++)
                {
                    dp[i+1][j+1][k]=(dp[i+1][j+1][k]+(n-j)*k*dp[i][j][k])%mod; //佔據的新的一行所能放的可能
                    dp[i+1][j][k+1]=(dp[i+1][j][k+1]+(m-k)*j*dp[i][j][k])%mod; //佔據的新的一列所能放的可能
                    if(dp[i+1][j+1][k]>=mod) dp[i+1][j+1][k]%=mod;  //mod太多會超時,微弱優化
                    if(dp[i+1][j][k+1]>=mod) dp[i+1][j+1][k]%=mod;
                    ll p=j*k-i; //計算有多少個可以放的交點
                    if(p<=0) continue;  //不能放就跳過
                    dp[i+1][j][k]=dp[i+1][j][k]+p*dp[i][j][k]; //放交點不增加行列
                    if(dp[i+1][j][k]>=mod) dp[i+1][j][k]%=mod;
                }
            }
        }
        printf("%lld\n",dp[n*m][n][m]%mod);
    }
    return 0;
}

相關文章