2018多校第九场1004(HDU 6415) DP

本以为是个找规律的题一直没找出来。。。

题目:给你一个n*m的矩阵和1-n*m个数,问有多少种情况满足纳什均衡的点只有一个。纳什均衡点是指这个元素在所在行和所在列都是最大的。

思路:吉老师直播的思路:(DP O(n^4)) 可以考虑从大到小的填充这个矩阵,设dp[cnt][i][j]是已经填充了cnt个数,i行可以放置数,j列可以放置数。

有3个状态转移过程:

1:选择在一个不是可放置行列交叉点的一个列上的某一点放置一个数,则放置之后会产生一个新的可放置行,每一列的可选择位置是n-i个,则dp[cnt+1][i+1][j]=dp[cnt][i][j]*j*(n-i);

2:选择行上不是交叉点的一点,原理同上,dp[cnt+1][i][j+1]=dp[cnt][i][j]*i*(m-j);

3:选择行和列的交叉点,则一共有i*j的交叉点,已经占用了cnt个,则可选择i*j-cnt+1个,dp[cnt+1][i][j]=dp[cnt][i][j]*(i*j-cnt+1);

代码:

#include<bits/stdc++.h>
using namespace std;
int dp[2][85][85];
int n,m,mod;
void update(int& a,long long c){
	a=(a+c)%mod;
}
void solve(){
	int Next,now=0;
	memset(dp,0,sizeof(dp));
	dp[0][1][1]=n*m;
	for(int cnt=2;cnt<=n*m;cnt++){
		Next=now^1;
		memset(dp[Next],0,sizeof(dp[Next]));
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++){
				if(dp[now][i][j]){
					update(dp[Next][i+1][j],1ll*dp[now][i][j]*j*(n-i));
					update(dp[Next][i][j+1],1ll*dp[now][i][j]*(m-j)*i);
					update(dp[Next][i][j],1ll*dp[now][i][j]*(i*j-cnt+1));
				}
			}
		now=Next;
	}
	printf("%d
",dp[now][n][m]);
}
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		scanf("%d%d%d",&n,&m,&mod);
		solve();
	}
} 

  

原文地址:https://www.cnblogs.com/pkgunboat/p/9512875.html