jzoj 4779. 【GDOI2017模拟9.14】鞍点

question

这题题目全是图,就不贴了(感觉好多题都是图。。。)

Solution

正解DP

我们设f[i][j]f[i][j]表示放到第i个鞍点,其中的最大值为j的方案数。
我们使放置的鞍点的大小严格不下降(这样计算较方便)
而后,我们将f[i][j]f[i][j]推到下一个:f[i+1][j+k]0&lt;=k&lt;=njf[i+1][j+k](0&lt;=k&lt;=n-j) 这里的n<m
转移方程很容易得到:
f[i+1][j+k]+=f[i][j]yh[k][nj]yh[k][mj]jc[k]M[i][(nj)k+(mj)kkkk]f[i+1][j+k]+=f[i][j] *yh[k][n-j] *yh[k][m-j] *jc[k]*M[i][(n-j) *k+(m-j) *k-k *k-k]
其中yh[i][j]yh[i][j]表示C(i,j)C(i,j),M[i][j]表示iji^j
最后我们就用容斥来搞一搞就可以了。

code

#include<cstdio>
#define N 2010
#define ll long long
using namespace std;
ll jc[N],yh[N][N],M[11][N*N],f[11][N],ans=0;
int n,m,K,mo;

void ycl()
{
	if (n>m) n=n+m,m=n-m,n=n-m;
	jc[0]=1;
	for (int i=1;i<=m;i++)
		jc[i]=jc[i-1]*i%mo,yh[1][i]=i;
	for (int i=2;i<=m;i++)
		for (int j=i;j<=m;j++)
			yh[i][j]=(yh[i][j-1]+yh[i-1][j-1])%mo;
	M[0][0]=1;
	for (int i=1;i<=K;i++)
	{
		M[i][0]=1;
		for (int j=1;j<=n*m;j++)
			M[i][j]=M[i][j-1]*i%mo;
	}
}

int main()
{
	scanf("%d%d%d%d",&n,&m,&K,&mo);
	ycl();f[0][0]=1;
	for (int i=0;i<K;i++)
		for (int j=0;j<=n;j++)
		{
			if (!f[i][j]) continue;
			(f[i+1][j]+=f[i][j])%=mo;
			for (int k=1;k<=n-j;k++)
				(f[i+1][j+k]+=f[i][j]*yh[k][n-j]%mo*yh[k][m-j]%mo*jc[k]%mo*M[i][(n-j)*k+(m-j)*k-k*k-k]%mo)%=mo;
		}
//	printf("%lld
",f[K][n]);
	for (int i=1,j=1;i<=n;i++,j=-j)
		(ans+=f[K][i]*M[K][(n-i)*(m-i)]%mo*j%mo)%=mo;
	printf("%lld
",(ans+mo)%mo);
	return 0;
}
转载需注明出处。
原文地址:https://www.cnblogs.com/jz929/p/11817550.html