牛客2019湘潭大学程序竞赛

官方题解

Hchat

  题目大意:中文题~~~~~~~~~~~~~~~~~~

  没看出是分组背包,一开始时就觉得像dp,但感觉三个循环可能会超时,没敢写,后来没其他想法了,还是试了一下。首先定义的dp[i][j]就是到第i天时,生气值为j的最少在线时间,那么如果我们知道第i天的生气值为j的最少在线时间b[i][j],那么转移过程就很好转移了,就是dp[i][j+k]=min(dp[i][j],dp[i-1][j]+b[i][k]),意思就是枚举到第i-1天生气值为j的情况,以及第i天生气值为k的情况,那么到第i天生气值为j+k的情况就相应更新。

  而b[i][j],怎么处理出来呢,我们先处理个a[i][j]为,第i天前j个小时的生气值的前缀和,然后对于每一天i,我们枚举个上线时间j和下线时间k,这样在线时间就是k-j+1,而在这段时间上线会造成的生气值就是a[i][m]-(a[i][k]-a[i][j-1]),相应地更新就好,详情见代码。

 1 #include<cstdio>
 2 #include<vector>
 3 #include<algorithm>
 4 using namespace std;
 5 const int inf=0x3f3f3f3f;
 6 int dp[250][250],a[250][250],b[250][250];
 7 char s[250];
 8 int main()
 9 {
10     int t,n,m,K;
11     scanf("%d",&t);
12     while(t--)
13     {
14         scanf("%d%d%d",&n,&m,&K);
15         for(int i=0;i<=n;i++)
16             for(int j=0;j<=K;j++)//前面值初始化m,wrong了三发 
17                 dp[i][j]=b[i][j]=inf;
18         for(int i=1;i<=n;i++)
19         {
20             scanf("%s",s+1);
21             for(int j=1;j<=m;j++)//处理前缀和 
22                 a[i][j]=a[i][j-1]+s[j]-'0';
23         }
24         int sq;
25         for(int i=1;i<=n;i++)
26         {
27             sq=a[i][m];//当天最多累计的生气值是sq
28             for(int j=sq;j<=K;j++)
29                 b[i][j]=0;//那么对于sq及之后的生气值最少上线时间都是0 
30             for(int j=1;j<=m;j++)//枚举上线时间 
31                 for(int k=j;k<=m;k++)//枚举下线时间 
32                 {
33                     sq=a[i][m]-(a[i][k]-a[i][j-1]);//如果在这个时间段下线,当天累计的生气值 
34                     b[i][sq]=min(b[i][sq],k-j+1);
35                 }
36         }
37         dp[0][0]=0;
38         for(int i=1;i<=n;i++)
39             for(int j=0;j<=K;j++)//枚举前i-1天,生气值为j的情况 
40                 for(int k=0;j+k<=K;k++)//枚举第i天,生气值为k的情况 
41                     dp[i][j+k]=min(dp[i][j+k],dp[i-1][j]+b[i][k]); //更新前i天,生气值为j+k的情况 
42         int ans=inf;
43         for(int i=0;i<=K;i++)
44             ans=min(ans,dp[n][i]);
45         printf("%d\n",ans);
46     }
47     return 0;
48 }
爱的魔力转圈圈

G,E等待更新

猜你喜欢

转载自www.cnblogs.com/LMCC1108/p/10816405.html