【cofun1373】中國象棋(cchess)
Description
在N行M列的棋盤上,放若干個炮(可以是0個),使得沒有任何一個炮可以攻擊另一個炮。 請問有多少种放置方法,中國象棋中炮的行走方式大家應該很清楚吧.
Input Format
兩個整數n,m
Output Format
方案總數 mod 9999973
Sample Input
1 3
Sample Output
7
Hint
【數據規模】30%的數據 n,m<=6
50%的數據n,m中至少有一個不超過8
100%的數據n,m<=100
雖然有取模,仍建議使用int64
- 分析:
- 對於50%的數據:n,m 中至少有一個不超過8
可以考慮狀壓,把情況dfs出來再DP,類似炮兵陣地。 - 對於100%的數據:類似組合數學的方法【網上看的。。but我覺得更像是普通的DP 2333】
題目很坑 ,“中國象棋中炮的行走方式大家應該很清楚吧”。。然鵝肯定有人不清楚【比如我SZO】,科普來了~23333, 反正最終會get到:每一行每一列最多隻能有兩隻棋子。於是推出了→
*轉移方程:
- 對於50%的數據:n,m 中至少有一個不超過8
f[i][j][k] = f[i - 1][j][k];//不放棋子
if (j)
f[i][j][k] += f[i - 1][j - 1][k] * (m - j + 1 - k);//在一個原來的空列上添加一隻棋子
if (k && j + 1 <= m)
f[i][j][k] += f[i - 1][j + 1][k - 1] * (j + 1);//把一個原有一隻棋子的列變爲有兩隻棋子的列
if (j > 1)
f[i][j][k] += f[i - 1][j - 2][k] * ((m - j + 2 - k) * (m - j + 1 - k) / 2);//在兩個原來的空列上分別添加一隻棋子
if (k > 1 && j + 2 <= m)
f[i][j][k] += f[i - 1][j + 2][k - 2] * ((j + 2) * (j + 1) / 2);//把兩個原有一隻棋子的列分別變爲有兩隻棋子的列
if (j && k)
f[i][j][k] += f[i - 1][j][k - 1] * j * (m - j - k + 1);//在一個原來的空列上添加一隻棋子,並把一個原有一隻棋子的列變爲有兩隻棋子的列
f[i][j][k]: 到i行爲止,有j列放一隻棋子,k列放兩隻棋子。
【雖然有點麻煩但是好理解~有個問題 爲啥在兩個空列上分別添加不等下一回DP而要先轉移呢?明天去問同學~【莫名Flag
- 媽耶我可能傻了。。因爲是枚舉到該行,所以放兩個列是在該行放兩個,放一個列是在該行放一個,如果等到下一回循環,那就是在下一行放,這是不一樣的。
好尷尬-_-||問了一個神犇,可是每次都是他回覆前我就突然開竅了。。QAQ
- 代碼:
#include <bits/stdc++.h>
using namespace std;
const long long MO = 9999973;
int n, m, i, j, k;
long long f[105][105][105], ans;
inline int read()
{
int x = 0, w = 1;
char ch = 0;
while(ch < '0' || ch > '9')
{
if (ch == '-')
w = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9')
x = x * 10 + ch - '0', ch = getchar();
return x * w;
} //讀入優化
inline void write(long long x)
{
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}//輸出優化
int main()
{
n = read(), m = read();
//讀入【本po代碼補全設了讀入優化,懶得刪了~見諒=w=
memset(f, 0, sizeof(f));
f[0][0][0] = 1;
for(i = 1; i <= n; i ++)
for(j = 0; j <= m; j ++)
for(k = 0; k + j <= m; k ++)
{
f[i][j][k] = f[i - 1][j][k];
if (j)
f[i][j][k] += f[i - 1][j - 1][k] * (m - j + 1 - k);
if (k && j + 1 <= m)
f[i][j][k] += f[i - 1][j + 1][k - 1] * (j + 1);
if (j > 1)
f[i][j][k] += f[i - 1][j - 2][k] * ((m - j + 2 - k) * (m - j + 1 - k) / 2);
if (k > 1 && j + 2 <= m)
f[i][j][k] += f[i - 1][j + 2][k - 2] * ((j + 2) * (j + 1) / 2);
if (j && k)
f[i][j][k] += f[i - 1][j][k - 1] * j * (m - j - k + 1);
f[i][j][k] %= MO;
}
//狀態轉移
for(i = 0; i <= m; i ++)
for(j = 0; j + i <= m; j ++)
ans = (ans + f[n][i][j]) % MO;
write(ans);
//統計答案並輸出【輸出優化原因同上,不過真的蠻省時的QUQ
return 0;
}
碼了兩回qwq剛上手沒有及時保存的好習慣ORZ閃退了TAT
睡覺啦~晚安安。O(∩_∩)O