codevs 3289 花匠

题目:codevs 3289 花匠

链接:http://codevs.cn/problem/3289/

 

这道题有点像最长上升序列,但这里不是上升,是最长“波浪”子序列。用动态规划可以解决,方程类似最长上升子序列:

f[i]=max(f[j])  ( 1≤j≤i-1 && ( (f[j]%2=1 && A[j]<A[i] ) || (j%2=0 && A[j]>A[i]) )  )

p[i]=max(p[i])  (  1≤j≤i-1 && ( (p[j]%2=1 && A[j]>A[i] ) || (j%2=0 && A[j]<A[i]) )  )

结果:

ans=max(f[n],p[n])

...写出来,很恶心的方程,因为题目中是有两种情况,第一种是 第一个元素 < 第二个元素 开始的波浪序列,另一种是 第一个元素 > 第二个元素 开始的波浪序列。我这里的f[i]是第一种情况算出来的最长波浪序列,p[i]是第二种情况算出来的最长波浪序列,然后最后的答案是两者之间选一个最大的。这样用o(n²)的算法可以达成,但是注意,题目中的数据量是10,000 ,肯定时间要超,所以还是要用优化。

最长上升子序列中可以用线段树优化,那么这里怎么优化呢?

我的笨笨做法是开4个线段树:maxfj[],maxfo[],maxpj[],maxpo[]。

maxfj[]维护f[i]是奇数的最大值,maxfo[]维护f[i]是偶数的最大值。

maxpj[]维护p[i]是奇数的最大值,maxpo[]维护p[i]是偶数的最大值。

因为f[i]中,当f[i]是奇数的时候,区间是1到A[i]-1中的最大值,而当f[i]是偶数的时候,区间是A[i]+1到n的最大值(因为是严格单调,所以要+1或-1)。

               当p[i]是奇数的时候,区间是A[i]+1到n的最大值,而当p[i]是偶数的时候,区间是1到A[i]-1中的最大值。

所以不能同时维护,要分开来,因此就是4个线段树。

当然,A[i]的值很大,要做离散化。

大致思路就是这样吧。

 

附代码:

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<iostream>
  4 using namespace std;
  5 const int maxn=100010;
  6 
  7 int n,maxfj[maxn*4],maxfo[maxn*4],f[maxn],p[maxn],maxpj[maxn*4],maxpo[maxn*4];
  8 
  9 struct u
 10 {
 11     int v,r;
 12     bool operator <(const u &rhs) const
 13     {
 14         return v<rhs.v;
 15     }
 16 }A[maxn];
 17 
 18 bool cmp(u a,u b)
 19 {
 20     return a.r<b.r;
 21 }
 22 
 23 int w,v;
 24 void updatefj(int o,int L,int R)
 25 {
 26     if(L==R) maxfj[o]=max(maxfj[o],v);
 27     else
 28     {
 29         int M=(L+R)/2;
 30         if(w<=M) updatefj(o*2,L,M); else updatefj(o*2+1,M+1,R);
 31         maxfj[o]=max(maxfj[o*2],maxfj[o*2+1]);
 32     }
 33 }
 34 
 35 int y1,y2,ans;
 36 void queryfj(int o,int L,int R)
 37 {
 38     if(y1<=L && R<=y2) ans=max(ans,maxfj[o]);
 39     else
 40     {
 41         int M=(L+R)/2;
 42         if(y1<=M) queryfj(o*2,L,M);
 43         if(y2>M) queryfj(o*2+1,M+1,R);
 44     }
 45 }
 46 void updatefo(int o,int L,int R)
 47 {
 48     if(L==R) maxfo[o]=max(maxfo[o],v);
 49     else
 50     {
 51         int M=(L+R)/2;
 52         if(w<=M) updatefo(o*2,L,M); else updatefo(o*2+1,M+1,R);
 53         maxfo[o]=max(maxfo[o*2],maxfo[o*2+1]);
 54     }
 55 }
 56 
 57 void queryfo(int o,int L,int R)
 58 {
 59     if(y1<=L && R<=y2) ans=max(ans,maxfo[o]);
 60     else
 61     {
 62         int M=(L+R)/2;
 63         if(y1<=M) queryfo(o*2,L,M);
 64         if(y2>M) queryfo(o*2+1,M+1,R);
 65     }
 66 }
 67 void updatepj(int o,int L,int R)
 68 {
 69     if(L==R) maxpj[o]=max(maxpj[o],v);
 70     else
 71     {
 72         int M=(L+R)/2;
 73         if(w<=M) updatepj(o*2,L,M); else updatepj(o*2+1,M+1,R);
 74         maxpj[o]=max(maxpj[o*2],maxpj[o*2+1]);
 75     }
 76 }
 77 
 78 void querypj(int o,int L,int R)
 79 {
 80     if(y1<=L && R<=y2) ans=max(ans,maxpj[o]);
 81     else
 82     {
 83         int M=(L+R)/2;
 84         if(y1<=M) querypj(o*2,L,M);
 85         if(y2>M) querypj(o*2+1,M+1,R);
 86     }
 87 }
 88 
 89 void updatepo(int o,int L,int R)
 90 {
 91     if(L==R) maxpo[o]=max(maxpo[o],v);
 92     else
 93     {
 94         int M=(L+R)/2;
 95         if(w<=M) updatepo(o*2,L,M); else updatepo(o*2+1,M+1,R);
 96         maxpo[o]=max(maxpo[o*2],maxpo[o*2+1]);
 97     }
 98 }
 99 
100 void querypo(int o,int L,int R)
101 {
102     if(y1<=L && R<=y2) ans=max(ans,maxpo[o]);
103     else
104     {
105         int M=(L+R)/2;
106         if(y1<=M) querypo(o*2,L,M);
107         if(y2>M) querypo(o*2+1,M+1,R);
108     }
109 }
110 
111 int main()
112 {
113     cin>>n;
114     for(int i=1;i<=n;i++) cin>>A[i].v,A[i].r=i;
115     //离散化 
116     sort(A+1,A+n+1);
117     for(int i=1,nw=1;i<=n;i++)
118     {
119         f[i]=1,p[i]=1;//顺便做的f[],p[]初始化 
120         if(A[i+1].v!=A[i].v) nw++,A[i].v=nw-1;
121         else A[i].v=nw;
122     } 
123     sort(A+1,A+n+1,cmp);
124      
125     w=A[1].v,v=f[1];
126     updatefj(1,1,n);
127     updatepj(1,1,n);
128 
129     for(int i=2;i<=n;i++)
130     {
131         y1=1,y2=A[i].v-1,ans=0;
132         if(y2>=y1) queryfj(1,1,n);//注意,因为有A[i]-1,所以要判断区间的存在 
133         y1=A[i].v+1,y2=n;
134         if(y2>=y1) queryfo(1,1,n);
135         f[i]=ans+1;
136         v=f[i],w=A[i].v;
137         if(f[i]%2==1) updatefj(1,1,n);
138         else updatefo(1,1,n);
139         
140         y1=1,y2=A[i].v-1,ans=0;
141         if(y2>=y1) querypo(1,1,n);
142         y1=A[i].v+1,y2=n;
143         if(y2>=y1) querypj(1,1,n);
144         p[i]=ans+1;
145         v=p[i],w=A[i].v;
146         if(p[i]%2==1) updatepj(1,1,n);
147         else updatepo(1,1,n);
148     }
149     
150     cout<<max(f[n],p[n]);
151     return 0;
152 }

 

posted @ 2017-01-07 18:15  Frank的成长之路  阅读(150)  评论(0编辑  收藏  举报