您的位置:首页 > 产品设计 > UI/UE

2013 多校第一场 hdu 4604 Deque

2013-07-24 12:35 357 查看
hdu 4604

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4604

题目大意:给你一个序列和一个双端队列,维持队列里是不下降的,问你一个一个加序列里的元素,队列的最大的长度是多少。

思路:首先,只考虑一个单调上升的双端队列,那么对于序列 A 和 队列 Q,找出以 Ai 为首的最长上升子序列和最长下降子序列,那么 Q 能维持的最大长度为这两个长度之和。现在,题目中的元素是可以重复的,那么,先求出以 Ai 为首的最长不下降子序列和最长不上升子序列,那么 Q 能维持的最大长度 = 这两个的长度之和 - 这两个序列中 Ai 个数的最小值。

以上都是解题报告里说的,自己比赛做的时候,因为情况太多了,进来又出去的,选了某个,又影响后面的,脑子很乱,根本没想到这一点,但是的确脑子里有出现过求最长递增子序列,没有深究下去,也没有发现他这个双端队列两端能进出的本质吧。。同时,有了思路,这道题最关键的地方还是在于判重,要深入理解LIS O(nlogn)这个算法的过程,其实当当前处理元素为 Ai 时,找到它的 pos ,那么d[1]~d[ pos ] 这里面存的就是以它为结尾的最长序列,再分别二分求出这两个序列中 Ai 的个数就行了。

代码如下:

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

const int INF = 0x0fffffff ;

const int MAXN = 100011 ;

int n;

int a[MAXN],d[2][MAXN];

int tot0,tot1;

int ans;

void lis()
{
d[0][1]=a
;
tot0=1;
d[1][1]=a
;
tot1=1;
for(int i=n-1;i>=1;i--)
{
int pos0;
if(a[i]>=d[0][tot0])
{
tot0++;
d[0][tot0]=a[i];
pos0 = tot0;
}
else
{
pos0 = upper_bound(d[0]+1,d[0]+tot0+1,a[i])-d[0];
d[0][pos0] = a[i];
}

int pos1;
if(a[i]<=d[1][tot1])
{
tot1++;
d[1][tot1] = a[i];
pos1  = tot1;
}
else
{
int l = 1,r = tot1;
while(l<r)
{
int m = l+r>>1;
if(d[1][m]>=a[i])
{
l=m+1;
}
else
{
r = m;
}
}
pos1 = l;
d[1][pos1] = a[i];
}
int f0 = pos0-(lower_bound(d[0]+1,d[0]+pos0+1,a[i])-d[0])+1;
int l = 1,r = pos1;
while(l<r)
{
int m = l+r>>1;
if(d[1][m]==a[i])
{
r= m;
}
else if(d[1][m]>a[i])
l = m+1;
else r = m-1;
}
int f1 = pos1 - l+1;
//printf("pos0 = %d,pos1 = %d,f0 = %d,f1 = %d\n",pos0,pos1,f0,f1);
ans = max(ans,pos0+pos1-min(f0,f1));
}
}

int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
ans=1;
lis();
printf("%d\n",ans);
}
return 0;
}
/*
10
1 2 1 3 2 1 3 1 2 2
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: