Cutlet
题解
很简单的一道dp题
定义为在前
秒内另一面煮了
秒时翻面的总数。这方程式也十分好想,
,注意,只有在区间
中才会进行翻转的赋值。
时间复杂度,明显会T,空间上也要加滚动数组才过得去,考虑优化。
首先,只有在区间内才会翻转,所以区间外的空档可以之间跳过去,这也是为什么需要要用背面时间赋值。
其次,我们发现每个区间内如果要翻转次数是不会超过2的,所以可以分别枚举翻的时间,只翻一次枚举时间点,翻两次枚举时间段长度,可以用单调队列来维护最优决策点。
由于,总的时间复杂度不会超过
,可以过。
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005
typedef long long LL;
typedef pair<int,int> pii;
const LL mo=1e9+7;
const LL INF=0x7f7f7f7f;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
int n,k,l[105],r[105],id,dp[2][MAXN],t;
int head,tail,q[MAXN];
signed main(){
scanf("%d %d",&n,&k);
memset(dp,0x7f,sizeof(dp));dp[0][0]=0;
for(int i=1;i<=k;i++){
scanf("%d %d",&l[i],&r[i]);t^=1;
for(int j=0;j<=n;j++)dp[t][j]=dp[t^1][j];
for(int j=0;j<=min(n,r[i]);j++){
while(head<tail&&dp[t^1][j]<=dp[t^1][q[tail-1]])tail--;
while(head<tail&&q[head]<j-r[i]+l[i])head++;q[tail++]=j;
dp[t][j]=min(dp[t][j],dp[t^1][q[head]]+2);
}
head=tail=0;
for(int j=r[i];j>=0;j--){
while(head<tail&&dp[t^1][r[i]-j]<=dp[t^1][q[tail-1]])tail--;
while(head<tail&&q[head]<l[i]-j)head++;q[tail++]=r[i]-j;
dp[t][j]=min(dp[t][j],dp[t^1][q[head]]+1);
//printf("%d %d:%d\n",i,j,dp[t][j]);
}
}
if(dp[t][n]<INF-1)printf("Full\n%d",dp[t][n]);
else puts("Hungry");
return 0;
}