USACO 2018 January Contest Platinum A: Lifeguards 题解

将所有的区间按左端点从小到大排序

我们处理那些被完全包含的区间,这些区间即使删除也不会使答案变坏

这样先删一波,如果发现这种小区间的个数多于k,就可以直接算答案了

否则我们要dp

设dp[i][j]为考虑到第i个区间,已经删除了j个区间,且第i个区间没有被删除的情况下最大的覆盖长度

显然有状态转移方程dp[i][j]=max(dp[k][j-i-k-1]+第i个区间贡献的覆盖)

这个方程相当于枚举上一个没有被删除的区间k,然后将k+1~i-1全部删除

但我们看到这个转移是O(n)的,所以总复杂度为O(n*n*k),不能接受

考虑优化dp转移

对于第i个区间,设其左端点为l

我们先看一看方程,会发现对dp[i][j]产生贡献的i'-j'=i-1-j

1. 对于i之前的那些右端点<=l的区间,它们与i没有重叠部分,所以只要在它们当中取max,再加上第i个区间的长度即可

2. 对于那些与i有重叠部分的区间,在当前区间右移的时候,这些dp的贡献会变,但相对大小不会变,所以可以维护一个单调队列,dp[i][j]对应的单调队列的编号为i-1-j,每次先把队头的那些已经跑到左边的区间弹出去(算成1的贡献),然后取队头就是当前的有重叠的状态中的最大答案

然后当前dp值算出来以后要插进对应的单调队列中(编号为i-j的单调队列),如果队尾状态加上与当前状态的右端点差还没有当前状态的dp值大的话,就把它从队尾弹出

这样总复杂度O(n*k)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define LB long double
#define x first
#define y second
#define Pair pair
#define pb push_back
#define pf push_front
#define mp make_pair
#define LOWBIT(x) x & (-x)
using namespace std;

const int MOD=1e9+7;
const LL LINF=2e16;
const int INF=2e9;
const int magic=348;
const double eps=1e-10;

inline int getint()
{
	char ch;int res;bool f;
	while (!isdigit(ch=getchar()) && ch!='-') {}
	if (ch=='-') f=false,res=0; else f=true,res=ch-'0';
	while (isdigit(ch=getchar())) res=res*10+ch-'0';
	return f?res:-res;
}

int n,k;
int maxn[100048];
deque q[100048];
int dp[100048][101];
Pair a[100048];bool exist[100048];
Pair x[100048];int x_top=0;

struct node
{
	int val;
	int nv;
	int from;
	bool type;
}b[200048];int tot=0;
Pair Pos[200048];
vector fake;

int c[200048];
inline bool update(int x,int delta)
{
	while (x<=n*2)
	{
		c[x]+=delta;
		x+=LOWBIT(x);
	}
}
inline int query(int x)
{
	int res=0;
	while (x)
	{
		res+=c[x];
		x-=LOWBIT(x);
	}
	return res;
}

bool cmp_y(Pair x,Pair y)
{
	return x.y=n)
	{
		printf("0\n");
		return 0;
	}
	sort(a+1,a+n+1);
	for (i=1;i<=n;i++)
	{
		b[++tot].val=a[i].x;b[tot].from=i;b[tot].type=false;
		b[++tot].val=a[i].y;b[tot].from=i;b[tot].type=true;
	}
	sort(b+1,b+tot+1,cmp);
	for (i=1;i<=tot;i++)
		if (!b[i].type) Pos[b[i].from].x=i; else Pos[b[i].from].y=i;
	for (i=1;i<=tot;i++)
		if (!b[i].type)
			update(i,1);
		else
		{
			update(Pos[b[i].from].x,-1);
			if (query(Pos[b[i].from].x)) fake.pb(b[i].from);
		}
	if (int(fake.size())>=k)
	{
		int ans=0,max_right=0;
		for (i=1;i<=n;i++)
		{
			if (max_right<=a[i].x)
			{
				ans+=a[i].y-a[i].x;
			}
			else if (max_right>=a[i].y) 
			{
				continue;
			}
			else
			{
				ans+=a[i].y-max_right;
			}
			max_right=max(max_right,a[i].y);
		}
		printf("%d\n",ans);
		return 0;
	}
	k-=int(fake.size());
	memset(exist,true,sizeof(exist));
	for (i=0;i


你可能感兴趣的:(USACO 2018 January Contest Platinum A: Lifeguards 题解)