题目来源:https://www.luogu.org/problem/show?pid=2051#sub
状态很难想。本题难就难在如何定状态。
再看题解之前,我一点思路也没有。看到题解的状态表示后,我立刻知道怎么做了。
f[i][j][k]表示至第i行,有j列放1个,有k列放2个。
这样f[i][j][k]即为第i行不放、放1个、放2个的数量总和。
状态转移方程很长,用到组合的相关知识。
i=1时需特殊处理。
详见代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
#include <queue>
#include <string>
using namespace std;
long long f[101][101][101]={0};
const long long mod=9999973;
long long c(long long n,long long m) {
if (m == 0)return 1;
long long l = n - m + 1;
long long ans = 1;
long long a[100] = {0};
int cnt = 0;
for (long long i = n; i >= n - m + 1; i--)a[++cnt] = i;
while (m > 1) {
for (int i = 1; i <= cnt; i++)
if (a[i] % m == 0) {
a[i] /= m;
break;
}
m--;
}
for (int i = 1; i <= cnt; i++)ans = (ans * a[i]) % mod;
return ans;
}
int main() {
ios::sync_with_stdio(false);
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= m; j++) {
for (int k = 0; k <= m; k++) {
if (j + k <= m) {
if (i == 1) {
if (k == 0) {
if (j == 1)f[i][j][k] = m;
if (j == 2)f[i][j][k] = c(m, 2);
if (j == 0)f[i][j][k] = 1;
}
} else {
if (j + 2 <= m && k - 2 >= 0)
f[i][j][k] =
(f[i][j][k] + f[i - 1][j + 2][k - 2] * (c(j + 2, 2))) % mod;
if (j - 2 >= 0 && m - k - j >= 0)
f[i][j][k] =
(f[i][j][k] + f[i - 1][j - 2][k] * (c((m - k - j + 2), 2))) % mod;
if (k - 1 >= 0 && m - k - j + 1 > 0)
f[i][j][k] =
(f[i][j][k] + f[i - 1][j][k - 1] * (j * (m - k - j + 1))) % mod;
if (j - 1 >= 0 && m - j - k + 1 > 0)
f[i][j][k] =
(f[i][j][k] + f[i - 1][j - 1][k] * (m - j - k + 1)) % mod;
if (j + 1 <= m && k - 1 >= 0)
f[i][j][k] =
(f[i][j][k] + f[i - 1][j + 1][k - 1] * (j + 1)) % mod;
f[i][j][k] = (f[i][j][k] + f[i - 1][j][k]) % mod;
}
}
}
}
}
long long tot = 0;
for (int i = 0; i <= m; i++) {
for (int j = 0; j <= m; j++) {
tot += f[n][i][j];
}
}
cout << tot % mod;
return 0;
}