hdu 4604 Deque(最长上升与下降子序列-能够重复)

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

这个题解有点问题,暂时没时间改,还是参考别人的吧

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <queue>
#include <vector>
#define maxn 100500
using namespace std;

const int INF = 0x3f3f3f;

int a[maxn];
int s1[maxn],s2[maxn];
int ans;
int n;

int search_lower_bound(int l,int h,int m){
    if(l == h) return l;
    int mid = (l + h)/2;
    if(s1[mid] <= m)  return search_lower_bound(mid+1,h,m);
    else              return search_lower_bound(l,mid,m);
}
int search_upper_bound(int l,int h,int m){
    if(l == h) return l;
    int mid = (l + h)/2;
    if(s2[mid] >= m)  return search_upper_bound(mid+1,h,m);
    else             return search_upper_bound(l,mid,m);
}

int main()
{
//    if(freopen("input.txt","r",stdin)== NULL)  {printf("Error\n"); exit(0);}

    int T;
    cin>>T;
    while(T--){
        cin>>n;
        for(int i=0;i<n;i++) scanf("%d",&a[i]);
        for(int i=0;i<=n/2;i++){
            int temp;
            temp = a[n-i-1]; 
            a[n-i-1] = a[i];
            a[i] = temp;
        }  
        s1[0] = s2[0] = a[0];
        int rear1 = 0,rear2 = 0;
        ans = 0;
        for(int i=1;i<n;i++){
            int temp1,temp2;
            
            if(s1[rear1] < a[i]) temp1 = ++rear1;
            else{
                temp1 = search_lower_bound(0,rear1,a[i]);
                if(s1[temp1] == a[i]){ 
                    for(int i=++rear1;i>temp1;i--)  s1[i] = s1[i-1]; 
                    temp1++; // printf("&&&&&& %d\n",rear1);
                }
            }
            s1[temp1] = a[i];
            
            if(s2[rear2] > a[i]) temp2 = ++rear2;
            else{
                temp2 = search_upper_bound(0,rear2,a[i]);
                /*if(s2[temp2] == a[i]){
                    for(int i=++rear2;i>temp2;i--)  s2[i] = s2[i-1]; 
                    temp2++;  printf("****** %d\n",rear2);
                }*/
            }   
            s2[temp2] = a[i];
            ans = max(ans,temp1+temp2+1);
        } 
        cout<<ans<<endl;
    }
}
View Code

 

 这题虽然过了,但存在一个问题。是数据弱了点。正确的思路:

(引用)

考虑题目的一个简化版本:使双端队列单调上升。对于序列A和队列Q,找到队列中最早出现的数字Ax,则Ax将Q分成的两个部分分别是原序列中以Ax开始的最长上升和最长下降序列,答案即为这两者之和的最大值。而对于本题,由于存在相同元素,所以只要找到以Ax 为起点的最长不下降序列和最长不上升序列的和,然后减去两个里面出现Ax次数的最小值即可。

我忽略了下降中的元素可重复,应该要考虑,在减去两个里面都存在的Ax重复次数;

 

所以有了大神的思路写出全新的代码:

 1 #include <cstdio>
 2 #include <cmath>
 3 #include <algorithm>
 4 #include <iostream>
 5 #include <cstring>
 6 #include <queue>
 7 #include <vector>
 8 #define maxn 105000
 9 using namespace std;
10 
11 const int INF = 0x3f3f3f;
12 
13 int d1[maxn],d3[maxn];
14 int g1[maxn],g2[maxn];
15 int a[maxn],b[maxn];
16 int n;
17 
18 int main()
19 {
20     //if(freopen("input.txt","r",stdin)== NULL)  {printf("Error\n"); exit(0);}
21 
22     int T;
23     cin>>T;
24     while(T--){
25         cin>>n;
26         for(int i=n-1;i>=0;i--){
27             scanf("%d",&a[i]);
28             b[i] = -a[i];
29         }
30         for(int i=1;i<=n;i++){
31             g1[i] = INF;
32             g2[i] = INF;
33         } 
34         int ans = 0;
35         for(int i=0;i<n;i++){
36             int k1 = upper_bound(g1+1,g1+n+1,a[i]) - g1;
37             int k2 = upper_bound(g2+1,g2+n+1,b[i]) - g2;
38             int k3 = lower_bound(g2+1,g2+n+1,b[i]) - g2;
39             g1[k1] = a[i];
40             g2[k2] = b[i];
41             d1[i] = k1;
42             d3[i] = k3;
43             ans = max(ans,d1[i] + d3[i] - 1); 
44         }
45         printf("%d\n",ans);
46     }
47 }
48  
View Code

这才是正确的方法,太精妙了。

lower_bound()是binary_search()的特殊形式. 此函数搜索给定的序列[first, end)中val可插入的第一个位置; 或者说, 它返回序列中遇到的第一个不小于val的元素的迭代器, 如果所有元素都小于val则返回“end”. 从函数要求待搜索序列是有序的.

lower_bound()的返回值乃是一个指向val可以安全插入的位置的迭代器. 在比较函数f被指定之前, 默认使用<操作符进行排序.

而upper_bound()是则是允许重复;

求最长下降就把a[] 变为相反数 b[],求b[]的最长上升子序列;

 

 

posted @ 2013-07-23 22:07  等待最好的两个人  阅读(478)  评论(6编辑  收藏  举报