Caesar's Legions(CodeForces-118D) 【DP】

题目链接: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 }

 

posted @ 2019-10-13 22:52  xxmlala  阅读(171)  评论(0编辑  收藏  举报