題目描述
這次小可可想解決的難題和中國象棋有關,在乙個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
【分析】
特別神奇的狀態轉移
唉又是一道省選dp神題 還帶組合數= =
我手玩幾組資料之後發現行列貌似可以交換的
然後還是不會做 只好求助於各神犇 題解比較少= =湊個熱鬧
dp[i][j][k]表示在前i行中有j列已經有2個 有k列已經有1個 那麼0的個數就是m-j-k個
轉移方程看**
這一行可以不放
那麼直接加上dp[i-1][j][k]
放乙個的話
可以把一列0變成1
可以把一列1變成2
放兩個的話
可以把兩列0變成1
可以把兩列1變成2
還有 可以把一列0變成1 再把另外一列1變成2
關於組合數要說一下。。
放乙個好說 直接乘1或0的個數完事(加在任意乙個上面都是可以的)
放兩個的話 前兩個也好弄 直接c(n,2) (n為可選個數)
最後乙個呢 先乘上原來0的個數 再乘上原來1的個數 乘法原理嘛= =
【**】
//p2051 [ahoi2009]中國象棋
#include
#include
#include
#include
#include
#define ll long long
#define m(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using
namespace
std;
const
int mod=9999973;
ll f[105][105][105];
int n,m,ans;
int main()
fo(j,0,m)
fo(k,0,m-j)
ans=(ans+f[n][j][k])%mod;
printf("%d\n",ans);
return
0;}
洛谷 P2051 AHOI2009 中國象棋
這道題主要是狀態很難想到 首先可以看出每行每列不能超過2個棋子 也就是說有0,1,2三種狀態 所以可以一行一行來處理 那就用放了0個棋子的列數是 那麼這個時候狀態轉移方程就非常好寫了。對於當前這一行可以不放,放乙個,放兩個棋子 表示沒有棋子的列,1表示有1個棋子的列。那麼有幾種情況 不放放乙個在 放...
洛谷 P2051 AHOI2009 中國象棋
題目 中國象棋 思路 首先是30分暴力 直接dfs就好。用row和col儲存狀態。include using namespace std define maxn 100 define read x scanf d x define md 9999973 int n,m int rw maxn 5 c...
洛谷 P2051 AHOI2009 中國象棋
這次小可可想解決的難題和中國象棋有關,在乙個n行m列的棋盤上,讓你放若干個炮 可以是0個 使得沒有乙個炮可以攻擊到另乙個炮,請問有多少種放置方法。大家肯定很清楚,在中國象棋中炮的行走方式是 乙個炮攻擊到另乙個炮,當且僅當它們在同一行或同一列中,且它們之間恰好 有乙個棋子。你也來和小可可一起鍛鍊一下思...