概述
Problem
CodeForces
大意就是一个长度为2n的01序列,给定k个不相交的区间,在区间内的元素允许与前一个元素不同,代价为1,要求使得01序列中0和1恰好是n个,问最小的代价。
Solution
可以设出这样的一个dp,f[i][j]表示到第i段结束,当前没烤的这面烤j分钟的最小翻面次数。如果你觉得这个状态不那么方便你也可以加一维0/1咯。
有这么一个性质,在一段区间内只有不翻/翻1次/翻2次的三种情况,分别考虑一下。为了方便表达,我们把上一次的状态用0表示。
不翻,决策就是00000
f [ i ] [ j ] = f [ i − 1 ] [ j ] f[i][j]=f[i-1][j] f[i][j]=f[i−1][j]
翻一次,那么应该是形如00111的决策,要注意这个转移中的反面与上次的反面并不是一面。枚举ri时的反面又多烤多少分钟,即后面连续1的长度:
f [ i ] [ j ] = min k ∈ [ 0 , l − r + 1 ] ( f [ i − 1 ] [ r i − j − k ] ) + 1 f[i][j]=min_{kin[0,l-r+1]}(f[i-1][r_i-j-k])+1 f[i][j]=k∈[0,l−r+1]min(f[i−1][ri−j−k])+1
这个好像可以用单调队列优化,但由于前驱状态的是-j,所以你可以把单调队列反着滑或者反着枚举k。
翻两次,形如00110的决策,枚举中间烤多少分钟,即中间连续1的长度:
f [ i ] [ j ] = min k ∈ [ 0 , l − r ] ( f [ i − 1 ] [ j − k ] ) + 2 f[i][j]=min_{kin[0,l-r]}(f[i-1][j-k])+2 f[i][j]=k∈[0,l−r]min(f[i−1][j−k])+2
这个也可以用单调队列优化。
最后再把数组滚动一下即可。时间复杂度 O ( n k ) O(nk) O(nk)。
Code
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#define rg register
using namespace std;
typedef long long ll;
const int maxn=100010,INF=0x3f3f3f3f;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
x=0;int f=0;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
if(f) x=-x;
}
struct data{
int l,r;
bool operator < (const data &t)const{return l<t.l;}
}a[maxn];
int n,k,len,f[2][maxn<<1];
deque<int> q;
void input()
{
read(n);read(k);
for(rg int i=1;i<=k;i++) read(a[i].l),read(a[i].r);
sort(a+1,a+k+1);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
int pre=0,cur=1;
input();
for(rg int i=1;i<=n+n;i++) f[cur][i]=INF;
for(rg int i=1;i<=k;i++)
{
pre^=1;cur^=1;len=a[i].r-a[i].l+1;
while(!q.empty()) q.pop_front();
memmove(f[cur],f[pre],sizeof(f[cur]));
for(rg int j=a[i].r;~j;j--)
{
while(!q.empty()&&f[pre][q.back()]>=f[pre][a[i].r-j]) q.pop_back();
q.push_back(a[i].r-j);
while(!q.empty()&&q.front()<a[i].l-j) q.pop_front();
if(!q.empty()) getmin(f[cur][j],f[pre][q.front()]+1);
}
while(!q.empty()) q.pop_front();
q.push_back(0);
for(rg int j=0;j<=n&&j<=a[i].r;j++)
{
while(!q.empty()&&f[pre][q.back()]>=f[pre][j]) q.pop_back();
q.push_back(j);
while(!q.empty()&&q.front()<=j-len) q.pop_front();
if(!q.empty()) getmin(f[cur][j],f[pre][q.front()]+2);
}
}
if(f[cur][n]>=INF) puts("Hungry");
else printf("Fulln%dn",f[cur][n]);
return 0;
}
最后
以上就是贪玩乌冬面为你收集整理的Codeforces 939F CutletProblemSolutionCode的全部内容,希望文章能够帮你解决Codeforces 939F CutletProblemSolutionCode所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复