您的位置:首页 > Web前端

UVA - 1471 Defense Lines

2016-08-21 23:21 435 查看
依然是紫书上的例题。。好难啊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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: