HDU多校第九次 6415 (dp

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;
}
posted @ 2018-08-21 19:42  ffgcc  阅读(82)  评论(0编辑  收藏  举报