question
这题题目全是图,就不贴了(感觉好多题都是图。。。)
Solution
正解DP
我们设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示放到第i个鞍点,其中的最大值为j的方案数。
我们使放置的鞍点的大小严格不下降(这样计算较方便)
而后,我们将
f
[
i
]
[
j
]
f[i][j]
f[i][j]推到下一个:
f
[
i
+
1
]
[
j
+
k
]
(
0
<
=
k
<
=
n
−
j
)
f[i+1][j+k](0<=k<=n-j)
f[i+1][j+k](0<=k<=n−j) 这里的n<m
转移方程很容易得到:
f
[
i
+
1
]
[
j
+
k
]
+
=
f
[
i
]
[
j
]
∗
y
h
[
k
]
[
n
−
j
]
∗
y
h
[
k
]
[
m
−
j
]
∗
j
c
[
k
]
∗
M
[
i
]
[
(
n
−
j
)
∗
k
+
(
m
−
j
)
∗
k
−
k
∗
k
−
k
]
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]
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]
其中
y
h
[
i
]
[
j
]
yh[i][j]
yh[i][j]表示
C
(
i
,
j
)
C(i,j)
C(i,j),M[i][j]表示
i
j
i^j
ij。
最后我们就用容斥来搞一搞就可以了。
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\n",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\n",(ans+mo)%mo);
return 0;
}