codeforces118d

题意:有n1个步兵和n2骑兵要排成一排,连续步兵数不能超过k1个,连续骑兵数不能超过k2个,问有几种排列方案

算是一个简单的dp,    我一开始的思想是设dp[i][j],i是n1+n2,j表示是步兵还是骑兵,但是发现这样不好转移,如果以后发现不好转移,可以加一维

                                     所以就把它变成了dp[i][j][k],i是步兵,j是骑兵,k是骑兵还是步兵,但是这样说好像不利于理解,不如这样说,i表示用了i个步兵,j表示用了j个骑兵,k表示当前用的是步兵还是骑兵,然后答案肯定是(dp[n1][n1][0]+dp[n1][n1][1])%mod

                                 然后接下来我就卡在了怎么转移上面了,其实我一开始的想法已经比较接近了,但是就是卡了那几下,没进去。其实这个是满足最优子结构的,这不用想,肯定没有后效性,但是怎么转移呢?

不妨假设,当前状态是dp[i][j][0],那么就是表示的状态是已经选了j个骑兵,i-1个步兵,然后当前再选一个步兵,那么怎么当前可以再选一个步兵,就是前面的步兵的数量的连续和不能超过k1,那么这样就可以推出状态转移方程了

下面是代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int mod=100000000;
 4 int n1,n2,k1,k2;
 5 int dp[110][110][2];
 6 int main(){
 7     scanf("%d%d%d%d",&n1,&n2,&k1,&k2);
 8     memset(dp,0,sizeof(dp));
 9     for(int i=1;i<=k1;i++)
10         dp[i][0][0]=1;
11     for(int i=1;i<=k2;i++)
12         dp[0][i][1]=1;
13     for(int i=1;i<=n1;i++){
14         for(int j=1;j<=n2;j++){
15             for(int k=1;k<=min(i,k1);k++) dp[i][j][0]=(dp[i][j][0]+dp[i-k][j][1])%mod;
16             for(int k=1;k<=min(j,k2);k++)  dp[i][j][1]=(dp[i][j][1]+dp[i][j-k][0])%mod;
17         }
18     }
19     printf("%d\n",(dp[n1][n2][0]+dp[n1][n2][1])%mod);    
20     return 0;
21 }
View Code

猜你喜欢

转载自www.cnblogs.com/pandaking/p/9941538.html
今日推荐