UVA - 1471 Defense Lines

依然是紫书上的例题。。好难啊TAT依旧不会做所以还是紫书上的思路(请结合紫书食用)。。f[i]与g[i]分别表示以下标i代表元素a[i]为终点与起点的最长连续上升子序列长度(跟紫书给的题解是反的。。注意一下。。),递归计算即可。关键在于插入操作,我的思路跟紫书上略微有点出入。我是用分类讨论来写的。当我们在枚举i的过程中,如果lower_bound返回了begin()迭代器那么我们这时是无需尝试更新maxx的,当返回值不是begin()的时候我们需要更新。然后讨论是否应该插入(a[i],f[i])这个二元组,当lower_bound的返回值(设为迭代器j)不是begin()迭代器的时候,如果j->a==a[i]那么我们不需要插入。因为二元组的排序在a相等的情况下,按f的顺序来排,这种情况下一定有f[i]<(j->f),否则不会返回begin()。第二种不需要插入的情况是(--j)->f>f[i],因为(--j)->a一定是小于a[i]的。其余的情况均需要插入。而且插入的位置就是j。所以从j开始删除不需要的二元组,然后插入(a[i],f[i])这个新的二元组。另外,当输入元素全都相同时,maxx会取到-1,修正为1即可(原因是之前更新maxx时,当lower_bound返回begin()时我们就没跟新maxx了,所以maxx一直是-1)。AC代码如下:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <set>
using namespace std;

int n,a[200005],f[200005],g[200005];
struct a_f
{
	int a,f;
	a_f(int aa=0,int ff=0):a(aa),f(ff){}
	bool operator <(const a_f &x)const
	{
	return a<x.a||(a==x.a&&f<x.f);
	}
};

set<a_f> mark;

int main(int argc, char const *argv[])
{
	int T;
	scanf("%d", &T);
	while(T--)
	{
		scanf("%d", &n);
		mark.clear();
		for(int i=0;i<n;i++)
		scanf("%d", &a[i]);
		f[0]=1;
		for(int i=1;i<n;i++)
		{
			if(a[i]>a[i-1])
			f[i]=f[i-1]+1;
			else
			f[i]=1;
		}
		g[n-1]=1;
		for(int i=n-2;i>=0;i--)
		{
			if(a[i]<a[i+1])
				g[i]=g[i+1]+1;
			else
				g[i]=1;
		}
		int maxx=-1;
		mark.insert(a_f(a[0],f[0]));
		for(int i=1;i<n;i++)
		{
//            for(set<a_f>::iterator k=mark.begin();k!=mark.end();k++)
//                printf("(%d %d) ", k->a,k->f);
//            printf("\n");
			a_f now(a[i],f[i]),t;
			set<a_f>::iterator j=mark.lower_bound(now);
			if(j!=mark.begin())
			{
				t=*(--j);
				maxx=max(maxx,g[i]+t.f);
				++j;
				if(j->a==a[i])
					continue;
				else if((--j)->f>f[i])
					continue;
				else
				{
					j++;
				while(j!=mark.end()&&j->f<=f[i])
					mark.erase(j++);
				mark.insert(now);
				}
			}
			else if(j->f<=f[i])
			{
				mark.erase(j);
				mark.insert(now);
			}
		}
		printf("%d\n", maxx>0? maxx:1);
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值