有 2×n 2 × n 的时间去煎一块两面的肉
给你 k k 个不相交时间区间 [li,ri] [ l i , r i ]
你可以在这些区间的时间内任意次翻转这块肉
问是否存在合法的方案使得两面恰好都只煎了 n n 分钟
求最少翻转次数
n≤105,k≤100 n ≤ 10 5 , k ≤ 100
考虑暴力 DP,fi,j D P , f i , j 表示前 i i 秒,没有被烤的那一面(简称为对面,另一面称正面)被烤了 j j 秒的最少翻转次数
fi,j=fi−1,j f i , j = f i − 1 , j 不翻转,上一个状态对面还是只烤了 j j 秒
fi,j=fi−1,i−j+1 f i , j = f i − 1 , i − j + 1 翻转,当前状态的正面是上一个状态的正面,总时间是 i, i , 当前对面烤了 j j 秒,那么正面就烤了 i−j i − j 秒
这个暴力显然是 O(n2) O ( n 2 ) 的,第二个转移只能在 [l,r] [ l , r ] 内发生
可以发现 O(nk) O ( n k ) 是可以过的,并且上一个 DP D P 中第一个转移几乎是没有用的,中间区间外的空挡是一路复制过去的
然后所有的区间又没有交集,设第 i i 区间右端点是 r r ,所以可以考虑这样一种 DP,fi,j D P , f i , j 表示前 r r 秒,对面烤了 j j 秒的最少翻转次数
然后我们可以想到,在一个区间里我们最多翻转两次,多的都可以转化为翻一次或者两次
枚举一个时间 k k ,表示翻转过后的正面多烤了 k k 秒, k≤r−l k ≤ r − l
考虑 fi,j f i , j 由什么转移过来
当前时间是 r r ,那么当前正面就烤了 r−j r − j 秒,因为多烤了 k k 秒
所以翻转点正面就烤了 r−j−k r − j − k 秒,又翻转之前当前正面是对面
fi,j=min{fi−1,r−j−k}+1 f i , j = m i n { f i − 1 , r − j − k } + 1
考虑用单调队列维护最优决策点 p=r−j−k p = r − j − k
当 k>r−l⇒p<r−j−(r−l)=l−j k > r − l ⇒ p < r − j − ( r − l ) = l − j 时就不合法了,并且可以发现这个是要倒推的
同样枚举一个时间 k k 表示翻转之后的正面烤了 k k 秒, k≤r−l k ≤ r − l
考虑到翻转两次相当于当前的对面翻过去多烤了 k k 秒,然后又翻回来了
⇒fi,j=min{fi−1,j−k}+2 ⇒ f i , j = m i n { f i − 1 , j − k } + 2
同样用单调队列维护最优决策点 p=j−k p = j − k
当 k>r−l⇒p<j−(r−l) k > r − l ⇒ p < j − ( r − l ) 时就不合法了,并且可以发现这个是要顺推的
可以发现这个 DP D P 是可以滚动的,注意数组大小
#include
#define fp(i,a,b) for(register int i=a,I=b+1;i
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(u) for(register int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
templateinline bool cmax(T&a,const T&b){return a1 :0;}
templateinline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char ss[1<<17],*A=ss,*B=ss;
inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?-1:*A++;}
templateinline void sd(T&x){
char c;T y=1;while(c=gc(),(c<48||571)if(c==45)y=-1;x=c-48;
while(c=gc(),4758)x=x*10+c-48;x*=y;
}
const int N=2e5+5,inf=1e9;
typedef int arr[N];
int n,k,p;arr q,f[2];
int main(){
#ifndef ONLINE_JUDGE
file("s");
#endif
sd(n),sd(k);int l,r,h,t;
f[0][0]=0;fp(i,1,n)f[0][i]=inf;
while(k--){
sd(l),sd(r);p^=1;h=1,t=0;
memcpy(f[p],f[p^1],sizeof f[p]);
fp(j,0,min(n,r)){
while(h<=t&&f[p^1][j]<=f[p^1][q[t]])--t;
while(h<=t&&q[h]q[++t]=j;
cmin(f[p][j],f[p^1][q[h]]+2);
}h=1,t=0;
fd(j,r,0){
while(h<=t&&f[p^1][r-j]<=f[p^1][q[t]])--t;
while(h<=t&&q[h]q[++t]=r-j;
cmin(f[p][j],f[p^1][q[h]]+1);
}
}
if(f[p][n]^inf)printf("Full\n%d",f[p][n]);
else puts("Hungry");
return 0;
}