這次小可可想解決的難題和中國象棋有關,在乙個n行m列的棋盤上,讓你放若干個炮(可以是0個),使得沒有乙個炮可以攻擊到另乙個炮,請問有多少種放置方法。大家肯定很清楚,在中國象棋中炮的行走方式是:乙個炮攻擊到另乙個炮,當且僅當它們在同一行或同一列中,且它們之間恰好 有乙個棋子。你也來和小可可一起鍛鍊一下思維吧!
一行包含兩個整數n,m,之間由乙個空格隔開。
總共的方案數,由於該值可能很大,只需給出方案數模9999973的結果。
輸入 #1複製
1 3輸出 #1複製
7樣例說明
除了3個格仔裡都塞滿了炮以外,其它方案都是可行的,所以一共有2*2*2-1=7種方案。
資料範圍
100%的資料中n和m均不超過100
50%的資料中n和m至少有乙個數不超過8
30%的資料中n和m均不超過6
鬼知道其實我一開始想用五維
好吧,不可行
part 1 審題
每行每列只能放至多兩粒棋子
part 2 狀態
好的,一格一格來是不可行了(看我的五維就知道了)
既然狀態明顯以行列為單位,那狀態就以行列設計
暫定,需要存的狀態:行,列,棋子數
其實現在是真不知道要考慮什麼具體狀態,先分析
part 3 轉移
說實話,格不行,那就一列一列列舉
再考慮棋子,在當前行,我們可以選擇:
1. 不放棋子
2. 放一粒棋子
3. 放兩粒棋子
廢話emmmm,好吧。
我們放棋子的時候,會造成什麼影響?
1. 有些沒棋子的列,有棋子了
2. 有些只有乙個棋子的列,有兩個棋子了
3. 有些有兩個棋子的列……好吧不能在這一列放棋子了
嗯?有什麼用?用處可大了
你想想,我們需要求的是什麼?
方案數。
如果我們能求出這一行不放、放一粒棋子、放兩粒棋子的方案數,這問題就圓滿了
怎麼求?
再看看上面的分析
當我們不放棋子的時候,方案數就等於上一行求出的總方案數
當我們放一粒棋子、放兩粒棋子的時候,列的狀態會改變
我們該怎麼表示列的狀態?然後存下方案數?
放棋子,列上的棋子數在增加,我們當然不可能存下每一列的具體狀態,畢竟我們不求具體的擺放方案
列的狀態與棋子數有關,卻與棋子具體在哪一行無關
棋子具體在哪一行,或行上的棋子具體在哪一列,只對於方案數有貢獻(然而這個可以用加法、乘法原理解決),對於接下來棋子的擺放無關聯
好的,狀態來了
如上,我們只存下列上的具體棋子數的列數就夠了
狀態:dp[第i行][只有乙個棋子的列有j列][有兩個棋子的列有k列] = 方案數
你問我為啥沒有空列的個數?
不就是m-j-k嘛
好吧,怎麼求方案?
看看我們曾經的分析:
再考慮棋子,在當前行,我們可以選擇:
1. 不放棋子
2. 放一粒棋子
3. 放兩粒棋子
我們放棋子的時候,會造成什麼影響?
1. 有些沒棋子的列,有棋子了
2. 有些只有乙個棋子的列,有兩個棋子了
3. 有些有兩個棋子的列……好吧不能在這一列放棋子了
好的狀態轉移出來了
分三種情況討論,不放,放一粒,放兩粒,分別計算
不放的時候:
放一粒棋子:
放兩粒棋子:
這裡解釋一下放兩粒棋子的轉移:
放空列:dp[i][j][k] += dp[i-1][j-2][k] * c2
m-(j-2)-k
放在有乙個棋子的列:dp[i][j][k] += dp[i-1][j+2][k-2] * c2
j+2乙個空列,乙個有棋:dp[i][j][k] += dp[i-1][j-1+1][k-1] * c1
m-j-(k-1) * c1
j求組合數:emm,通過觀察,1的就是本身,2的可以這麼求:
好了,over
1view code/**************************
2user:mandy.h.y
3language:c++
4problem:luogu 2051
5algorithm:
6**************************/7
8 #include9
#define max(x,y) ((x) > (y) ? (x) : (y))
10#define min(x,y) ((x) < (y) ? (x) : (y))
1112
using
namespace
std;
1314
const
int maxn = 105;15
const
int mod = 9999973;16
17int
n,m;
18long
long
dp[maxn][maxn][maxn];
1920 templateinline void read(t &x)
2627 templatevoid putch(const
t x)
3132 templatevoid put(const
t x)
3637
void
file()
4142
void
readdata()
4546
int c(int
x)49
50void
work()77}
78}79long
long ans = 0;80
for(int i = 0;i <= m; ++i)
81for(int j = 0;j <= m - i; ++ j)
8485
put(ans);86}
8788
intmain()
luogu2051中國象棋
題目描述 這次小可可想解決的難題和中國象棋有關,在乙個n行m列的棋盤上,讓你放若干個炮 可以是0個 使得沒有乙個炮可以攻擊到另乙個炮,請問有多少種放置方法。大家肯定很清楚,在中國象棋中炮的行走方式是 乙個炮攻擊到另乙個炮,當且僅當它們在同一行或同一列中,且它們之間恰好 有乙個棋子。你也來和小可可一起...
P2051 AHOI2009 中國象棋
這次小可可想解決的難題和中國象棋有關,在乙個 n 行 m 列的棋盤上,讓你放若干個炮 可以是 0個 使得沒有乙個炮可以攻擊到另乙個炮,且它們之間恰好 有乙個棋子。你也來和小可可一起鍛鍊一下思維吧!一行包含兩個整數 n,m之間由乙個空格隔開。總共的方案數,由於該值可能很大,只需給出方案數模 99999...
洛谷 2051 AHOI2009 中國象棋
題目描述 這次小可可想解決的難題和中國象棋有關,在乙個n行m列的棋盤上,讓你放若干個炮 可以是0個 使得沒有乙個炮可以攻擊到另乙個炮,請問有多少種放置方法。大家肯定很清楚,在中國象棋中炮的行走方式是 乙個炮攻擊到另乙個炮,當且僅當它們在同一行或同一列中,且它們之間恰好 有乙個棋子。你也來和小可可一起...