版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
- 主要思路,拆环,设置特定状态进行dp(多次dp)
多次dp,断环+强连
- 例题:一天有n小时,每天能花m小时睡觉,要花1h入睡(不回体力),睡着后回体力,每个时间点回不同体力,问体力最大值
- 思路:dp[i][j][0/1]表示第i小时,已睡j小时,当前是否在睡。分两个初始状态dp,一个是第一个小时没有深度睡眠,dp[1][0][0]=0,dp[1][1][1]=0;
代码
#include<bits/stdc++.h>
using namespace std;
int n,b,v[4000],dp[3][4000][3],mx;
int main()
{
scanf("%d%d",&n,&b);
for(int i=1;i<=n;i++)
scanf("%d",&v[i]);
memset(dp,-0x3f,sizeof(dp));
dp[1][1][1]=0;dp[1][0][0]=0;
mx=-1;
for(int i=2;i<=n;i++)
{
for(int j=i>b?b:i;j>=0;j--)
{
if(j>0)
dp[i&1][j][1]=dp[(i-1)&1][j-1][1]+v[i];
if(j>0&&dp[(i-1)&1][j-1][0]>dp[i&1][j][1])
dp[i&1][j][1]=dp[(i-1)&1][j-1][0];
dp[i&1][j][0]=dp[(i-1)&1][j][0];
if(dp[(i-1)&1][j][1]>dp[i&1][j][0])
dp[i&1][j][0]=dp[(i-1)&1][j][1];
}
}
if(dp[n&1][b][0]>mx)mx=dp[n&1][b][0];
if(dp[n&1][b][1]>mx)mx=dp[n&1][b][1];
memset(dp,0xcf,sizeof(dp));
dp[1][1][1]=v[1];
for(int i=2;i<=n;i++)
{
for(int j=b>i?i:b;j>=1;j--)
{
dp[i&1][j][0]=dp[(i-1)&1][j][0];
dp[i&1][j][1]=dp[(i-1)&1][j-1][1]+v[i];
if(dp[(i-1)&1][j-1][0]>dp[i&1][j][1])
dp[i&1][j][1]=dp[(i-1)&1][j-1][0];
if(dp[(i-1)&1][j][1]>dp[i&1][j][0])
dp[i&1][j][0]=dp[(i-1)&1][j][1];
}
}
if(dp[n&1][b][1]>mx)mx=dp[n&1][b][1];
cout<<mx;
}
化环为链,复制相连
思路:如题
例题:环路运输
代码:
#include<bits/stdc++.h>
#define N 2000005
using namespace std;
int x[N],n,nn,l=1,r,pos[N],ans;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&x[i]),x[i+n]=x[i];
nn=n+n;
for(int i=1;i<=nn;i++)
{
while(l<=r&&i-pos[l]>n/2)++l;
if(l<=r&&ans<x[pos[l]]+i-pos[l]+x[i])
ans=x[pos[l]]+i-pos[l]+x[i];
while(l<=r&&(i-pos[r]>n/2||x[pos[r]]+i-pos[r]<x[i]))--r;
pos[++r]=i;
}
printf("%d",ans);
}