zoukankan      html  css  js  c++  java
  • 洛谷P2051 中国象棋

    题目链接:https://www.luogu.com.cn/problem/P2051

    题意:nxm棋盘放棋子,每行每列都不能放超过2个棋子,求方案数

    为什么这题有状压dp的标签......我还一直在想状压怎么写,然而这个n,m<=100。

    正解是比较巧妙的dp。设f[i][j][k]表示到了第i行,有j列放了1个棋子,k列放了2个棋子的方案数,那么有转移方程:

    f[i][j][k]+=f[i-1][j][k],第i行不放棋子

    f[i][j][k]+=f[i-1][j-1][k]*(m-j-k+1),在一列没放棋子的放1个

    f[i][j][k]+=f[i-1][j+1][k-1]*(j+1),在一列放了1个棋子的放1个,使得这列放了2个棋子

    f[i][j][k]+=f[i-1][j-2][k]*C(m-k-j+2,2),在两列没放棋子的各放1个,使得这两列都放了1个

    f[i][j][k]+=f[i-1][j+2][k-2]*C(j+2,2),在两列放1个棋子的再各放1个,使得这两列放了2个

    f[i][j][k]+=f[i-1][j][k-1]*j*(m-k-j+1),在一列放0个的和一列放1个的,各放一个棋子,使得一列放1个,另外一列放2个

    注意每个转移方程的边界条件即可

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    const ll mod=9999973;
    ll f[110][110][110],n,m,i,j,k;
    
    int main(){
    	cin>>n>>m;
    	memset(f,0,sizeof(f));
    	f[0][0][0]=1;
    	for (i=1;i<=n;i++)
    	  for (j=0;j<=m;j++)
    	    for (k=0;k<=m;k++)
    	      if (j+k<=m&&j+k*2<=i*2){
    	      	f[i][j][k]=f[i-1][j][k];
    	      	if (j>=1) f[i][j][k]+=f[i-1][j-1][k]*(m-k-j+1);
    	      	if (k>=1) f[i][j][k]+=f[i-1][j+1][k-1]*(j+1);
    	      	if (j>=2) f[i][j][k]+=f[i-1][j-2][k]*(m-k-j+2)*(m-k-j+1)/2;
    	      	if (k>=1) f[i][j][k]+=f[i-1][j][k-1]*(m-j-k+1)*j;
    	      	if (k>=2) f[i][j][k]+=f[i-1][j+2][k-2]*(j+2)*(j+1)/2;
    	      	f[i][j][k]%=mod;
    		  }
    	ll ans=0;
    	for (i=0;i<=m;i++)
    	  for (j=0;j<=m;j++)
    	    if (i+j<=m&&i+j*2<=2*n) ans=(ans+f[n][i][j])%mod;
    	cout<<ans<<endl;
    	return 0;
    }
    

      

     

  • 相关阅读:
    js练习题2
    js样式
    js小练习
    css动画样式
    css盒子、布局样式
    css一般样式
    css样式、选择器
    html表格、表单
    html 标签
    mysql连接查询,子查询,联合查询
  • 原文地址:https://www.cnblogs.com/edmunds/p/13691915.html
Copyright © 2011-2022 走看看