題目鏈結
題目大意:求在\(n\)行\(m\)列的棋盤上放置若干個炮使得它們互不攻擊的方案數,對\(9999973\)取模動態規劃,計數
分析:沒有炮互相攻擊等價於沒有三個炮在同一行/列
考慮用\(f[i][m_1][m_2]\)表示前\(i\)行,有\(m_1\)列有乙個炮,\(m_2\)列有兩個炮的方案數
可以用刷表法降低思維難度
初始條件:
\(f[1][0][0] = 1\)
\(f[1][1][0] = m\)
\(f[1][2][0] = c_m^2\)
這個比較簡單,轉移可以大力分類討論,即討論第\(i + 1\)行的放置個數,以及放置方案
\(f[i + 1][m_1][m_2] += f[i][m_1][m_2]\)
\(f[i + 1][m_1 + 1][m_2] += f[i][m_1][m_2] \times (m - m_1 - m_2)\)
\(f[i + 1][m_1 - 1][m_2 + 1] += f[i][m_1][m_2] \times m_1\)
\(f[i + 1][m_1 + 2][m_2] += f[i][m_1][m_2] \times c_^2\)
\(f[i + 1][m_1][m_2 + 1] += f[i][m_1][m_2] \times m_1 \times (m - m_1 - m_2)\)
\(f[i + 1][m_1 - 2][m_2 + 2] += f[i][m_1][m_2] \times c_^2\)
然後注意一下邊界條件,避免非法狀態和非法轉移即可
#include using namespace std;
typedef long long ll;
const int maxn = 128,mod = 9999973;
int n,m;
ll f[maxn][maxn][maxn],ans;
inline ll c2(ll x)
int main()
for(int m1 = 0;m1 <= m;m1++)
for(int m2 = 0;m1 + m2 <= m;m2++)
ans += f[n][m1][m2],ans %= mod;
printf("%lld\n",ans);
return 0;
}
P2051 AHOI2009 中國象棋
這次小可可想解決的難題和中國象棋有關,在乙個 n 行 m 列的棋盤上,讓你放若干個炮 可以是 0個 使得沒有乙個炮可以攻擊到另乙個炮,且它們之間恰好 有乙個棋子。你也來和小可可一起鍛鍊一下思維吧!一行包含兩個整數 n,m之間由乙個空格隔開。總共的方案數,由於該值可能很大,只需給出方案數模 99999...
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 中國象棋 DP
這次小可可想解決的難題和中國象棋有關,在乙個n行m列的棋盤上,讓你放若干個炮 可以是0個 使得沒有乙個炮可以攻擊到另乙個炮,請問有多少種放置方法。大家肯定很清楚,在中國象棋中炮的行走方式是 乙個炮攻擊到另乙個炮,當且僅當它們在同一行或同一列中,且它們之間恰好 有乙個棋子。你也來和小可可一起鍛鍊一下思...