luogu 2051 AHOI2009 中國象棋

2022-07-17 05:42:11 字數 3261 閱讀 4118

這次小可可想解決的難題和中國象棋有關,在乙個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

1

/**************************

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()

view code

luogu2051中國象棋

題目描述 這次小可可想解決的難題和中國象棋有關,在乙個n行m列的棋盤上,讓你放若干個炮 可以是0個 使得沒有乙個炮可以攻擊到另乙個炮,請問有多少種放置方法。大家肯定很清楚,在中國象棋中炮的行走方式是 乙個炮攻擊到另乙個炮,當且僅當它們在同一行或同一列中,且它們之間恰好 有乙個棋子。你也來和小可可一起...

P2051 AHOI2009 中國象棋

這次小可可想解決的難題和中國象棋有關,在乙個 n 行 m 列的棋盤上,讓你放若干個炮 可以是 0個 使得沒有乙個炮可以攻擊到另乙個炮,且它們之間恰好 有乙個棋子。你也來和小可可一起鍛鍊一下思維吧!一行包含兩個整數 n,m之間由乙個空格隔開。總共的方案數,由於該值可能很大,只需給出方案數模 99999...

洛谷 2051 AHOI2009 中國象棋

題目描述 這次小可可想解決的難題和中國象棋有關,在乙個n行m列的棋盤上,讓你放若干個炮 可以是0個 使得沒有乙個炮可以攻擊到另乙個炮,請問有多少種放置方法。大家肯定很清楚,在中國象棋中炮的行走方式是 乙個炮攻擊到另乙個炮,當且僅當它們在同一行或同一列中,且它們之間恰好 有乙個棋子。你也來和小可可一起...