把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【CF939F】Cutlet(单调队列优化DP)

题目链接

  • \(0\sim 2n\)\(2n+1\) 个时刻,共 \(2n\) 个时间间隔。
  • 你需要烤一块肉,使得有恰好 \(n\) 个时间间隔烤正面,\(n\) 个时间间隔烤反面。
  • 给定 \(k\) 个无交区间,表示可以将肉翻面的时刻。
  • 求最小的翻面次数。
  • \(1\le n\le10^5\)\(0\le k\le100\)

单调队列优化 DP

把能翻面的看作一种区间,不能翻面的看作另一种区间。设 \(f_{i,j,0/1}\) 表示到第 \(i\) 个区间为止正面烤了 \(j\) 个时间间隔,当前在烤正(\(0\))/反(\(1\))面,这一状态的最小翻面次数。

无论哪种区间我们都可以选择不翻面,如果第三维为 \(0\) 就给第二维加上区间长度,如果第三维为 \(1\) 就不变第二维,进行转移。

而对于能翻面的区间我们至多翻面两次,决定这个区间过后烤的那一面是否改变。

假设区间长度为 \(len\)

如果翻面一次,\(f_{i,j,0}\) 可以从 \(f_{i-1,j-len+1\sim j,1}\) 转移,\(f_{i,j,1}\) 可以从 \(f_{i-1,j-len\sim j-1,0}\) 转移。

如果翻面两次,\(f_{i,j,0/1}\) 可以从 \(f_{i-1,j-len+1\sim j-1,1/0}\) 转移。

代码:\(O(nk)\)

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Rg register
#define RI Rg int
#define Cn const
#define CI Cn int&
#define I inline
#define W while
#define N 100000
#define K 100
#define Gmin(x,y) (x>(y)&&(x=(y)))
using namespace std;
int n,k,q[N+5],f[2*K+5][N+5][2];struct S {int l,r,op;}s[2*K+5];
int main()
{
	RI i,j,c=0,x,y,lst=0;for(scanf("%d%d",&n,&k),i=1;i<=k;++i) scanf("%d%d",&x,&y),
		!x&&++x,x<=y&&(x>lst+1&&(s[++c]=(S){lst+1,x-1,0},0),s[++c]=(S){x,lst=y,1},0);lst<2*n&&(s[++c]=(S){lst+1,2*n,0},0);//记录区间
	RI H,T;for(i=0;i<=c;++i) for(j=0;j<=n;++j) f[i][j][0]=f[i][j][1]=1e9;for(f[0][0][0]=0,i=1;i<=c;++i)
	{
		for(j=0;j<=n;++j) j+s[i].r-s[i].l+1<=n&&Gmin(f[i][j+s[i].r-s[i].l+1][0],f[i-1][j][0]),Gmin(f[i][j][1],f[i-1][j][1]);//不翻面
		if(!s[i].op) continue;
		for(H=1,T=0,j=0;j<=n;++j) {W(H<=T&&q[H]<=j-(s[i].r-s[i].l+1)) ++H;W(H<=T&&f[i-1][j][1]<f[i-1][q[T]][1]) --T;q[++T]=j,Gmin(f[i][j][0],f[i-1][q[H]][1]+1);}//1->0
		for(q[H=T=1]=0,j=1;j<=n;++j) {W(H<=T&&q[H]<j-(s[i].r-s[i].l+1)) ++H;W(H<=T&&f[i-1][j][0]<f[i-1][q[T]][0]) --T;Gmin(f[i][j][1],f[i-1][q[H]][0]+1),q[++T]=j;}//0->1
		if(s[i].l==s[i].r) continue;
		for(q[H=T=1]=0,j=1;j<=n;++j) {W(H<=T&&q[H]<=j-(s[i].r-s[i].l+1)) ++H;W(H<=T&&f[i-1][j][0]<f[i-1][q[T]][0]) --T;Gmin(f[i][j][0],f[i-1][q[H]][0]+2),q[++T]=j;}//0->1->0
		for(q[H=T=1]=0,j=1;j<=n;++j) {W(H<=T&&q[H]<=j-(s[i].r-s[i].l+1)) ++H;W(H<=T&&f[i-1][j][1]<f[i-1][q[T]][1]) --T;Gmin(f[i][j][1],f[i-1][q[H]][1]+2),q[++T]=j;}//1->0->1
	}return min(f[c][n][0],f[c][n][1])==1e9?puts("Hungry"):printf("Full\n%d\n",min(f[c][n][0],f[c][n][1])),0;
}
posted @ 2021-11-05 19:16  TheLostWeak  阅读(67)  评论(0编辑  收藏  举报