• 洛谷 P2051 [AHOI2009]中国象棋(多维dp)


    传送门


    解题思路

    设dp[i][j][k]为到前i行,有j列放了1个炮,k列放了两个炮的方案数。
    显然讨论各种情况,从i-1进行转移即可。
    可以滚动数组,但没必要。

    • 一个不放:方案数等于dp[i-1][j][k]。
    • 放一个,放在原来一个没有的列上:方案数等于dp[i-1][j-1][k]*(m-(j-1)-k)
    • 放一个,放在原来有一个炮的列上:方案数等于dp[i-1][j+1][k-1]*(j+1)
    • 放两个,全放在原来一个没有的列上:方案数等于dp[i-1][j-2][k]*(m-(j-2)-k)*(m-(j-2)-k-1)/2
    • 放连个,全放在原来有一个炮的列上:方案数等于dp[i-1][j+2][k-2]*(j+2)*(j+1)/2
    • 放两个,一个放在原来没有炮的列上,一个放在原来有一个炮的列上:方案数等于dp[i-1][j][k-1]*(m-j-(k-1))*j

    注意取模和边界判断即可。

    AC代码

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<iomanip>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int mod=9999973; 
    const int maxn=105;
    int n,m;
    long long dp[maxn][maxn][maxn];
    long long ans;
    inline long long c(int x){
    	return (long long)x*(x-1)/2;
    }
    int main(){
    	ios::sync_with_stdio(false);
    	cin>>n>>m;
    	for(int i=0;i<=n;i++) dp[i][0][0]=1;
    	for(int i=1;i<=n;i++){
    		for(int j=0;j<=m;j++){
    			for(int k=0;k<=m;k++){
    				if(j+k>m) break;
    				dp[i][j][k]=dp[i-1][j][k];
    				if(j>=1) dp[i][j][k]+=dp[i-1][j-1][k]*(m-j+1-k);
    				if(k>=1) dp[i][j][k]+=dp[i-1][j+1][k-1]*(j+1);
    				if(j>=2) dp[i][j][k]+=dp[i-1][j-2][k]*c(m-j+2-k);
    				if(k>=2) dp[i][j][k]+=dp[i-1][j+2][k-2]*c(j+2);
    				if(j>=1&&j-1+k<m) dp[i][j][k]+=dp[i-1][j][k-1]*(m-j+1-k)*j;
    				dp[i][j][k]%=mod;
    				if(i==n) ans=(ans+dp[i][j][k])%mod;
    			}
    		}
    	}
    	cout<<ans;
        return 0;
    }
    
  • 相关阅读:
    Java SSM 框架相关基础面试题
    JPanel JScrollPanel
    Spring MVC 的 Converter 和 Formatter
    JDesktopPane JInternalFrames
    Spring MVC 中的 forward redirect Flash属性
    Java Swing 中使用 EventQueue
    Java 中转换为String类型的四种方法
    Eclipse 安装使用 M2Eclipse 插件
    正则表达式
    Spring MVC 数据绑定和表单标签库
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/15253028.html
Copyright © 2020-2023  润新知