码迷,mamicode.com
首页 > 其他好文 > 详细

●BZOJ 3126 [Usaco2013 Open]Photo

时间:2018-01-01 23:31:13      阅读:163      评论:0      收藏:0      [点我收藏+]

标签:photo   .com   个数   bzoj   return   size   turn   line   min   

 

题链:

http://www.lydsy.com/JudgeOnline/problem.php?id=3126

题解:

单调队列优化DP,神奇。。
(好像某次考试考过,当时我用了差分约束+SPFA优化,然后过了。。。)


记 L[i] 表示i左边没有覆盖i点的区间中的最大的左端点
R[i] 表示覆盖i的区间中的最小的左端点的前一个位置,
那么,如果在i位置放一个点的话,在L[i]~R[i]里面也必须要放一个点。
(这两个数组可以O(N)计算前后缀最大最小值得到。)
即定义 DP[i] 为i位置放点时的总点数,
转移:DP[i]=max(DP[j])+1 (L[i]<=j<=R[i])
然后可以用单调队列优化。
和普通的单调队列有点不同,因为多了一个R[i]这个转移的右端点限制。

其实本质还是相同的~~

考虑到L[i],R[i]都单增,

所以在原来队列的首尾指针l,r的基础上多开一个rr指针就好了。

代码:

 

#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 200050
using namespace std;
int L[MAXN],R[MAXN],F[MAXN];
int N,M;
int main(){
	static int Q[MAXN],l,r,_r;
	scanf("%d%d",&N,&M);
	for(int i=1;i<=N+1;i++) R[i]=i-1;
	for(int i=1,l,r;i<=M;i++){
		scanf("%d%d",&l,&r);
		L[r+1]=max(L[r+1],l);
		R[r]=min(R[r],l-1);
	}
	for(int i=2;i<=N+1;i++) L[i]=max(L[i-1],L[i]);
	for(int i=N;i>=1;i--) R[i]=min(R[i],R[i+1]);
	l=_r=r=1; Q[1]=0;
	for(int i=1;i<=N+1;i++){
		while(_r<=R[i]&&_r<=N){
			if(F[_r]==-1){_r++; continue;}
			while(l<=r&&F[Q[r]]<=F[_r]) r--;
			Q[++r]=_r; _r++;
		}
		while(l<=r&&Q[l]<L[i]) l++;
		if(l<=r) F[i]=F[Q[l]]+(i!=N+1?1:0);
		else F[i]=-1;
	}
	printf("%d",F[N+1]);
	return 0;
}

 

  

 

●BZOJ 3126 [Usaco2013 Open]Photo

标签:photo   .com   个数   bzoj   return   size   turn   line   min   

原文地址:https://www.cnblogs.com/zj75211/p/8168933.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!