欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

洛谷 - P2051 [AHOI2009]中国象棋(计数dp)

发布时间:2024/4/11 54 豆豆
生活随笔 收集整理的这篇文章主要介绍了 洛谷 - P2051 [AHOI2009]中国象棋(计数dp) 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

题目链接:点击查看

题目大意:给出一个 n * m 的棋盘,可以在任意位置放置 “炮”,问一共可以放置多少种可行的方案

题目分析:转换题意,就是问每一行、每一列至多有两个棋子的方案数

因为我们并不关心具体到每一列、每一行的那些棋子是如何分布的,只关注相应的行和列有多少个棋子,所以我们设置状态 dp[ i ][ j ][ k ][ t ],意义为到了第 i 行时,有 j 列没有放置棋子,有 k 列放置了一个棋子,有 t 列放置了两个棋子,又因为 j + k + t 恒等于 m,所以可以省略掉最后一维

转移的话分为三大种情况,六个小情况分别讨论:

  • 第 i 行不放棋子:dp[ i ][ j ][ k ] += dp[ i - 1 ][ j ][ k ]
  • 第 i 行放一个棋子:
  • 放在空列上:dp[ i ][ j ][ k ] += dp[ i - 1 ][ j + 1 ][ k - 1 ] * ( j + 1 )
  • 放在有一个棋子的列上:dp[ i ][ j ][ k ] += dp[ i - 1 ][ j ][ k + 1 ] * ( k + 1 )
  • 第 i 行放两个棋子:
  • 都放在空列上:dp[ i ][ j ][ k ] += dp[ i - 1 ][ j + 2 ][ k - 2 ] * C( j + 2 )
  • 都放在有一个棋子的列上:dp[ i ][ j ][ k ] += dp[ i - 1 ][ j ][ k + 2 ] * C( k + 2 )
  • 各放一个:dp[ i ][ j ][ k ] += dp[ i - 1 ][ j + 1 ][ k ] * ( j + 1 ) * k
  • C( x ) 是组合数学的 C( x , 2 )

    代码:
     

    //#pragma GCC optimize(2) //#pragma GCC optimize("Ofast","inline","-ffast-math") //#pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=110;const int mod=9999973;LL dp[N][N][N];//dp[i][j][k]:到了第i行,有j列没有棋子,有k列有一个棋子的方案数 LL C(int n)//返回C(n,2) {return (1LL*n*(n-1)/2)%mod; }int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);int n,m;scanf("%d%d",&n,&m);dp[0][m][0]=1;for(int i=1;i<=n;i++)for(int j=0;j<=m;j++)for(int k=0;k<=m;k++){dp[i][j][k]=dp[i-1][j][k];if(k-1>=0)dp[i][j][k]+=dp[i-1][j+1][k-1]*(j+1);dp[i][j][k]+=dp[i-1][j][k+1]*(k+1);if(k-2>=0)dp[i][j][k]+=dp[i-1][j+2][k-2]*C(j+2);dp[i][j][k]+=dp[i-1][j][k+2]*C(k+2);dp[i][j][k]+=dp[i-1][j+1][k]*(j+1)*k;dp[i][j][k]%=mod;}LL ans=0;for(int j=0;j<=m;j++)for(int k=0;k<=m;k++)if(j+k<=m)ans=(ans+dp[n][j][k])%mod;printf("%lld\n",ans);return 0; }

     

    超强干货来袭 云风专访:近40年码龄,通宵达旦的技术人生

    总结

    以上是生活随笔为你收集整理的洛谷 - P2051 [AHOI2009]中国象棋(计数dp)的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。