zoukankan      html  css  js  c++  java
  • Luogu P2051 [AHOI2009]中国象棋

    Luogu P2051 [AHOI2009]中国象棋

    是道好题.jpg√

    戳个链接吧:Luogu P2051 [AHOI2009]中国象棋

    SOLUTION:

    首先一定不要被你谷的标签迷惑

    这道题状压撑死算是拿部分分的一个方法(而且即使数据范围很小咱也没想明白怎么状压

    这道题数据范围显然不是可以状态压缩的范围

    还是老老实实考虑正常dp吧:

    首先N,M<=100,那么我们可以依据【五一qbxt】day3 动态规划中,大致推断这是一道(O(N^3))的做法的题(事实也是这样的

    首先分析可以知道,一行或一列中,最多有2个炮要不然肯定会互相攻击

    然后这个题的状态就感觉很难想(color{#ffffff}{不会告诉你们状态是touli题解的lz})

    我们设(dp[i][x][y])表示前i行,有x列的炮的数量为1,y列炮的数量为2(当然剩下的m-x-y列炮的数量为0)时的方案数;

    考虑初始只有一行的状态:

    显然第一行有三种放法:

    1. 不放任何炮,此时方案数为1;(dp[1][0][0]=1)
    2. 放一个炮,那么m个位置每个位置都有可能,方案数为m (dp[1][1][0]=m)
    3. 放两个炮,这样的方案数应该是(C _m^2) (dp[1][2][0]=C_m^2)

    这也就是初始的状态(反正咱是这么写的

    然后考虑转移:

    对于(dp[i][x][y])

    有以下n种可能:

    1. 第i行不放“炮“,那么(dp[i][x][y]+=dp[i-1][x][y])//有1个棋子的列和有2个棋子的列显然是不改变的
    2. 第i行放一个“炮”,那么又分两种可能:
      1. 未放这个棋子的时候,所在一列是空的。那么显然放上这一个棋子之后,炮的数量为1的列会增加1,因此第i-1列的炮的数量为1的列应该是x-1,那么当为第i-1行时,空行的数量为(m-(x-1)-y),我们可以选择任意一个空行操作, 所以(dp[i][x][y]+=dp[i-1][x-1][y]*(m-y-x+1))
      2. 未放这个棋子的时候,所在的一列已经有一个棋子了。如果放上这一个棋子,那么炮的数量为1的列会减少1,炮的数量为2的列会增加1,因此第i-1行炮的数量为1的列应该是有x+1,炮的数量为2的列应该为y-1,而符合所在一列已经有一个棋子的列数有x+1列,因此(dp[i][x][y]+=dp[i-1][x+1][y-1]*(x+1))
    3. 第i行放两个“炮”,分为三种可能:
      1. 之前的位置是空的。放上棋子后,增加了两个炮的数量为1的列,炮的数量为2的列并没有变化,而选择这两个空行的可能的方案数为(C_{m-y-x+2}^2),因此(dp[i][x][y]+=dp[i-1][x-2][y]*C_{m-y-x+2}^2)
      2. 之前的位置一个是空一个有棋子。我们(color{red}{仔细})推算一下,可以推出i-1的dp状态:(dp[i-1][x][y-1])而位置的选择为:(m-y-x+1)*x (空行数量 *炮的数量为1的列数量),那么(dp[i][x][y]+=dp[i-1][x][y-1] * (m-y-x+1) * x)
      3. 之前的位置都是有棋子的。也就是说,放上棋子之后,炮的数量为1的列减少了2,炮的数量为2的列增加了2,然后符合条件的组合有:(C_{x+2}^2),则(dp[i][x][y]+=dp[i-1][x+2][y-2]*C_{x+2}^2)

    当然以上所有都不能数组越界的,所以要判断x和y的值是否>0,>1;

    另外在循环时,因为一共只有m列,因此i+j的值要<=m,所以可以直接将y从m-x开始循环到0而不用从0~m都循环一遍;

    CODE:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    inline int read() {
    	int ans=0;
    	char last=' ',ch=getchar();
    	while(ch>'9'||ch<'0') last=ch,ch=getchar();
    	while(ch>='0'&&ch<='9') ans=(ans<<1)+(ans<<3)+ch-'0',ch=getchar();
    	if(last=='-') ans=-ans;
    	return ans;
    }
    const int mod=9999973;
    int n,m;
    int dp[110][110][110];
    
    long long C(int m,int k) {
    	if(m<k) return 0;
    	long long ans=1;
    	for(int i=m;i>m-k;i--)
    		ans=ans*i;
    	long long fm=1;
    	for(int i=k;i>=2;i--) 
    		fm=fm*i;
    	ans/=fm;
    	return ans%mod;
    }
    
    int main() {
    	n=read();
    	m=read();
    	dp[1][0][0]=1;
    	dp[1][1][0]=m;
    	dp[1][2][0]=C(m,2);
    	for(int i=2;i<=n;i++) {
    		for(int x=0;x<=m;x++) {
    			for(int y=m-x;y>=0;y--) {
    				dp[i][x][y]=dp[i-1][x][y];
    				if(x>0) 
    					dp[i][x][y]=(dp[i][x][y]+dp[i-1][x-1][y]%mod*(m-y-x+1)%mod)%mod;
    				if(y>0) {
    					dp[i][x][y]=(dp[i][x][y]+dp[i-1][x][y-1]%mod*(m-x-y+1)%mod*x%mod)%mod;
                        dp[i][x][y]=(dp[i][x][y]+dp[i-1][x+1][y-1]%mod*(x+1)%mod)%mod;
                    }
                    if(x>1) 
    					dp[i][x][y]=(dp[i][x][y]+dp[i-1][x-2][y]%mod*C(m-y-x+2,2)%mod)%mod;
    				if(y>0)
    					
    				if(y>1) 
    					dp[i][x][y]=(dp[i][x][y]+dp[i-1][x+2][y-2]%mod*C(x+2,2)%mod)%mod;
    			}
    		}
    	}
    	long long ans=0;
    	for(int x=0;x<=m;x++) 
    		for(int y=m-x;y>=0;y--) 
    			ans=(ans+dp[n][x][y])%mod;
    	printf("%lld",ans);
    	return 0;
    }
    
  • 相关阅读:
    hibernate_0100_HelloWorld
    MYSQL子查询的五种形式
    JSF是什么?它与Struts是什么关系?
    nop指令的作用
    htmlparser实现从网页上抓取数据(收集)
    The Struts dispatcher cannot be found. This is usually caused by using Struts tags without the associated filter. Struts tags are only usable when the
    FCKeditor 在JSP上的完全安装
    Java遍历文件夹的2种方法
    充电电池和充电时间说明
    吃知了有什么好处
  • 原文地址:https://www.cnblogs.com/zhuier-xquan/p/11806676.html
Copyright © 2011-2022 走看看