這次小可可想解決的難題和中國象棋有關,在乙個 n 行 m 列的棋盤上,讓你放若干個炮(可以是 0個),使得沒有乙個炮可以攻擊到另乙個炮,
且它們之間恰好 有乙個棋子。你也來和小可可一起鍛鍊一下思維吧!
一行包含兩個整數 n,m之間由乙個空格隔開。
總共的方案數,由於該值可能很大,只需給出方案數模 9999973 的結果。
輸入 #1
1 3輸出 #1
樣例說明
除了 3 個格仔裡都塞滿了炮以外,其它方案都是可行的,所以一共有 2×2×2−1=7 種方案。
對於 30%的資料,n 和 m 均不超過 6。
對於 50% 的資料,n 和 m 至少有乙個數不超過 8。
對於 100% 的資料,1≤n,m≤100。
對於前30%的資料,我們可以爆搜拿部分暴力分。
然後,我們就需要開始考慮正解。
首先,根據中國象棋的芝士,每行每列只能放兩個炮(這不是廢話嗎)。
我們就可以根據這個列出方程
我們設 f[i][j][k]表示第i行,其中有j列放了乙個棋子,k列放了兩個棋子的方案數。
轉移:考慮第i行的放置情況
不放的情況 這時候我們可以直接由f[i-1][j][k]轉移過來
放乙個的情況,並且放在了之前沒有炮的列上,由於我們在沒有炮的一列放了乙個,會使放乙個炮的列數加1,
這種沒放炮的列一共有\(m-j-k+1\)列,統計一下就行了
放乙個炮,並且放在了之前就有乙個炮的列上,我們在乙個有乙個炮的列上放了乙個,就會導致放兩個炮的列加一.
放乙個炮列的減一,再加上有j-1列可以放。就是 f[i-1][j+1][k-1] * (j+1)
放兩個炮的情況,兩個炮都放在沒有炮的列上,會導致放乙個炮的列加二,並且這樣的列一共有\(m-j-k+2\)
利用組合數算出答案就解決了方程就是 f[i-1][j-2][k] * calc(m-j-k+2,2)
放兩個炮的情況,都放在之前放過兩個炮的列上,會導致放兩個炮的列加二,放乙個炮的列數減二,再加上這樣的列
一共有\(j+2\)列。 方程就可以寫成 f[i-1][j+2][k-2] * calc(j+2,2)
放兩個炮的情況,且乙個放在之前沒有炮的地方,另乙個放在之前有乙個炮的地方,這就會導致放兩個炮的數量加一。
放乙個炮的列數不變(加一後又減一) 再加上有\(j*(k-1)\)中情況,直接計算就okk了
答案就是\(\sum_^ \sum_^f[n][i][j]\)
這題,分類討論確實煩了點,令人想吐
#include#include#includeusing namespace std;
#define ll long long
const int p = 9999973;
int n,m;
ll c[110][110],f[110][110][110],ans;
void yych() }}
ll calc(int n,int m)
int main()
} }for(int i = 0; i <= m; i++) }
printf("%lld\n",ans);
return 0;
}
P2051 AHOI2009 中國象棋 (dp)
傳送門 n和m太大了,狀壓dp不行。換一種方式 定義f i j k 為前i行中有就 j 列放了乙個,k列放了2個的方案數。總共有m列,什麼也沒放的有 s m j k 列。第 i 行有三種選擇不放,放乙個 放s或j中,k已經放不下了 放兩個 全放s,乙個s乙個j,兩個j 需要注意一直保持 s j k ...
題解 P2051 AHOI2009 中國象棋
題目鏈結 題目大意 求在 n 行 m 列的棋盤上放置若干個炮使得它們互不攻擊的方案數,對 9999973 取模 動態規劃,計數 分析 沒有炮互相攻擊等價於沒有三個炮在同一行 列 考慮用 f i m 1 m 2 表示前 i 行,有 m 1 列有乙個炮,m 2 列有兩個炮的方案數 可以用刷表法降低思維難...
P2051 AHOI2009 中國象棋 DP
這次小可可想解決的難題和中國象棋有關,在乙個n行m列的棋盤上,讓你放若干個炮 可以是0個 使得沒有乙個炮可以攻擊到另乙個炮,請問有多少種放置方法。大家肯定很清楚,在中國象棋中炮的行走方式是 乙個炮攻擊到另乙個炮,當且僅當它們在同一行或同一列中,且它們之間恰好 有乙個棋子。你也來和小可可一起鍛鍊一下思...