bzoj 2006: [NOI2010]超级钢琴
Description
Input
Output
只有一个整数,表示乐曲美妙度的最大值。
Sample Input
3
2
-6
8
Sample Output
【样例说明】
共有5种不同的超级和弦:
音符1 ~ 2,美妙度为3 + 2 = 5
音符2 ~ 3,美妙度为2 + (-6) = -4
音符3 ~ 4,美妙度为(-6) + 8 = 2
音符1 ~ 3,美妙度为3 + 2 + (-6) = -1
音符2 ~ 4,美妙度为2 + (-6) + 8 = 4
最优方案为:乐曲由和弦1,和弦3,和弦5组成,美妙度为5 + 2 + 4 = 11。
HINT
Source
很久之前就听说过这是一道好题。。。今天看到菊儿子又再偷偷地切题,于是我也好奇的来看一下。。。
结果Orz其实菊开打的是主席树
题目是说
给定一个数列,求K个长度为[L,R]中的连续子序列(不能重复),使其和最大。
和最大的话显然是前K大的和嘛。。。
第一眼只会暴力。。。就是求出所有满足长度的连续子序列,然后sort。。。( n*(R-L+1)+n*(R-L+1)*log(R-L+1) )。。。萎得起飞,20分GG。。。
第三个部分分就很关键了。。。n很大而k等于1。。。
假如我们枚举起点,那么运用前缀和的思想,我们要做的其实是一个RMQ问题:
首先对原数列维护一个前缀和 a[i]数组,那么对于每一个起点i:
对于以该点为起点的长度合法连续子序列的最大值为 ∑(i+L-1<=j<=i+R-1) max(a[j]-a[i-1]);(不晓得打sigma);
发现到a[i-1]其实是不变的,即我们只需要对区间[i+L-1,i+R-1]求a[j]最大的j。。。那么就是RMQ的经典问题了。。。
这样第三个点的复杂度为 nlogn预处理+n的枚举起点。。。想到这里就真的没想出来了。。。。
那么我们由k=1推广到多个。。。(说得简单。。。)
这个推广真心巧妙。。。Orz;Orz;Orz;
1.用三元组(i, l, r)表示右端点为i,左端点在[l, r]之间和最大的区间([l, r]保证是对于i可行右端点区间的一个子区间),我们用堆维护一些这样的三元组。
2.假如某次最大值为(i, l, r),并且j为那个和最大区间的左端点,pop出来后,需要往堆中加入两个三元组(i, l, j-1)和(i, j+1, r)。
这样是什么意思呢???
这样其实就是每次选取了一个最优的三元组,然后把次优的三元组放进去;
(每个三元组的次优解的就是对于原来那个三元组强行把最优答案不取,即次优值在[l,j-1]中或[j+1,r]中取);
Orz贼有道理。。。
选取了K次之后就是答案。
复杂度:nlogn+k*log(n+k);
MDZZ 人生第一次ST表,打错了3次。。。竟然还过了样例
1 // MADE BY QT666 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 #include<iostream> 6 #include<queue> 7 #include<set> 8 #include<cstdlib> 9 #include<cstring> 10 #include<string> 11 #include<ctime> 12 #define lson num<<1 13 #define rson num<<1|1 14 #define int long long 15 using namespace std; 16 typedef long long ll; 17 const int N=1000050; 18 int gi() 19 { 20 int x=0,flag=1; 21 char ch=getchar(); 22 while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();} 23 while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); 24 return x*flag; 25 } 26 int n,k,L,R,a[N],ST[N][25],pre[25],pre2[N],ans; 27 struct data{int st,l,r,ed;}; 28 bool operator<(data x,data y){ 29 return a[x.ed]-a[x.st-1]<a[y.ed]-a[y.st-1]; 30 } 31 void makeST() 32 { 33 pre[0]=1;for(int i=1;i<=20;i++) pre[i]=pre[i-1]<<1; 34 pre2[0]=-1;for(int i=1;i<=n;i++) pre2[i]=pre2[i>>1]+1; 35 for(int i=1;i<=n;i++) ST[i][0]=i; 36 for(int j=1;j<=20;j++) 37 for(int i=1;i<=n;i++){ 38 if(i+pre[j]-1<=n){ 39 int x1=ST[i][j-1],x2=ST[i+pre[j-1]][j-1]; 40 if(a[x1]>a[x2]) ST[i][j]=x1; 41 else ST[i][j]=x2; 42 } 43 } 44 } 45 int query(int l,int r) 46 { 47 if(l==r)return l; 48 int x=pre2[r-l+1]; 49 int x1=ST[l][x],x2=ST[r-pre[x]+1][x]; 50 return a[x1]>a[x2]?x1:x2; 51 } 52 main() 53 { 54 n=gi(),k=gi(),L=gi(),R=gi(); 55 for(int i=1;i<=n;i++) a[i]=gi(),a[i]=a[i-1]+a[i]; 56 makeST(); 57 priority_queue<data,vector<data> >heap; 58 for(int i=1;i<=n;i++){ 59 if(i+L-1<=n){ 60 int x=min(i+R-1,n); 61 heap.push((data){i,i+L-1,x,query(i+L-1,x)}); 62 } 63 } 64 for(int i=1;i<=k;i++){ 65 data x=heap.top();heap.pop(); 66 ans+=a[x.ed]-a[x.st-1]; 67 if(x.ed-1>=x.l)heap.push((data){x.st,x.l,x.ed-1,query(x.l,x.ed-1)}); 68 if(x.ed+1<=x.r)heap.push((data){x.st,x.ed+1,x.r,query(x.ed+1,x.r)}); 69 } 70 printf("%lld",ans); 71 return 0; 72 }