题目链接:https://vjudge.net/problem/CodeForces-118D
题意:有n1名步兵和n2名骑兵,现在要将他们排成一列,并且最多连续k1名步兵站在一起,最多连续k2名骑兵站在一起,求方案数。
思路:dp[i][j][res1][res2],表示排好了i人,并且当前最后一个人是j(j=1表示步兵, j=2表示骑兵),res1、res2分别表示步兵、骑兵的剩余数量。
xxmlala:真的贼激动啊,有史以来第一次在比赛中做出来非状态压缩的dp!
代码如下:
1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 using namespace std;
5 const int mo=1e8;
6 long long dp[220][3][110][110];
7 int main(){
8 int n1,n2,k[3];
9 scanf("%d%d%d%d",&n1,&n2,&k[1],&k[2]);
10 memset(dp,-1,sizeof(dp));
11 int kk1=min(k[1],n1),kk2=min(k[2],n2);
12 for(int i=1;i<=kk1;i++)
13 dp[i][1][n1-i][n2]=1;
14 for(int i=1;i<=kk2;i++)
15 dp[i][2][n1][n2-i]=1;
16 for(int j=1;j<=n1+n2;j++){
17 for(int i=1;i<=2;i++){
18 int re[3];
19 for(re[1]=0;re[1]<=n1;re[1]++)
20 for(re[2]=0;re[2]<=n2;re[2]++){
21 if(dp[j][i][re[1]][re[2]]==-1)
22 continue;
23 int kFlag=min(k[3-i],re[3-i]);
24 int kt[3]={0};kt[3-i]=1;
25 for(int jj=1;jj<=kFlag&&jj+j<=n1+n2;jj++){
26 if(dp[jj+j][3-i][re[1]-kt[1]*jj][re[2]-kt[2]*jj]==-1)
27 dp[jj+j][3-i][re[1]-kt[1]*jj][re[2]-kt[2]*jj]=0;
28 dp[j+jj][3-i][re[1]-kt[1]*jj][re[2]-kt[2]*jj]+=dp[j][i][re[1]][re[2]]%mo;
29 dp[j+jj][3-i][re[1]-kt[1]*jj][re[2]-kt[2]*jj]%=mo;
30 }
31 }
32 }
33 }
34 long long ans=0;
35 if(dp[n1+n2][1][0][0]!=-1)
36 ans+=dp[n1+n2][1][0][0];
37 if(dp[n1+n2][2][0][0]!=-1)
38 ans+=dp[n1+n2][2][0][0];
39 ans%=mo;
40 printf("%I64d",ans);
41 return 0;
42 }