2020 hdu多校赛 第八场 1002 Breaking Down News
题意:
给你一个由 -1 1 0组成的数列(n<=1e6),要求你把这个数列分为若干子串,L<=每一段长度<=R,如果这一段内的和大于 0 则这一段的价值为 1 ,小于 0 为 -1 ,等于 0 为 0。
问你这些子串的和最大是多少。
首先,我们考虑如果没有L R限制该如何处理:
设 sum[i] 为1~i 的前缀和
如果 sum[ x ]<sum[ i ] ( x < i ),则 x+1~i 的区间和小于 0
如果 sum[ x ]=sum[ i ] ,则x+1~i 的区间和等于0
如果 sum[ x ]>sum[ i ],则x+1~i 的区间和大于0
设F[i]为 1~i 的最优解
我们就可以用sum[i]建权值线段树,表示前缀和为某值时F[i]最大为多少。
每次在-n~sum[i]-1 sum[i] sum[i]+1~n 里面去找最大值然后转移即可。
那么现在有了L R的限制我们应该怎么办呢?
因为 i 比 i+1 的合法转移区间只会少一个左端点多一个右端点。我们直接在线段树上修改即可。
而维护某个前缀和值的最大F[i]可以用可删除堆来实现。
不过,由于这一道题 ai只有 1 -1 0,相邻两个位置的前缀和最大也只差 1 ,我们也可以用三个堆来表示比sum[i] 小、等、大的解,每次把其中的某个不合法或新合法元素插入删除即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstdlib> 7 #include<queue> 8 #include<map> 9 #define N 1000005 10 using namespace std; 11 char xch,xB[1<<15],*xS=xB,*xTT=xB; 12 #define getc() (xS==xTT&&(xTT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xTT)?0:*xS++) 13 inline int read() 14 { 15 int x=0,f=1;char ch=getc(); 16 while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();} 17 while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();} 18 return x*f; 19 } 20 map<int,int> ma; 21 int T,n,L,R; 22 int A[N]; 23 int sum[N]; 24 int zz,B[N]; 25 struct no{ 26 int left,right,mid; 27 int mx; 28 }node[N*4]; 29 priority_queue<int> q1[N],q2[N]; 30 void build(int left,int right,int x) 31 { 32 node[x].left=left; 33 node[x].right=right; 34 node[x].mx=-1e7; 35 if(left==right) 36 { 37 return; 38 } 39 int mid=(left+right)>>1; 40 node[x].mid=mid; 41 build(left,mid,x<<1); 42 build(mid+1,right,x<<1|1); 43 } 44 int F[N]; 45 int get(int left,int right,int x) 46 { 47 if(left>right)return -1e7; 48 if(left==node[x].left&&right==node[x].right) 49 { 50 return node[x].mx; 51 } 52 int mid=node[x].mid; 53 if(left>mid) return get(left,right,x<<1|1); 54 else if(right<=mid)return get(left,right,x<<1); 55 else return max(get(left,mid,x<<1),get(mid+1,right,x<<1|1)); 56 } 57 void ch(int to,int x,int da) 58 { 59 if(node[x].left==node[x].right) 60 { 61 node[x].mx=da; 62 return; 63 } 64 int mid=node[x].mid; 65 if(to>mid) ch(to,x<<1|1,da); 66 else ch(to,x<<1,da); 67 node[x].mx=max(node[x<<1].mx,node[x<<1|1].mx); 68 } 69 int main() 70 { 71 T=read(); 72 while(T--) 73 { 74 n=read(); 75 L=read(); 76 R=read(); 77 ma.clear(); 78 zz=0; 79 for(int i=1;i<=n;i++) 80 { 81 A[i]=read(); 82 sum[i]=sum[i-1]+A[i]; 83 if(!ma[sum[i]]) 84 { 85 zz++; 86 B[zz]=sum[i]; 87 ma[sum[i]]=1; 88 } 89 F[i]=0; 90 } 91 if(!ma[0]) 92 { 93 zz++; 94 B[zz]=0; 95 ma[0]=1; 96 } 97 sort(B+1,B+zz+1); 98 for(int i=1;i<=zz;i++) 99 { 100 ma[B[i]]=i; 101 while(!q1[i].empty()) q1[i].pop(); 102 while(!q2[i].empty()) q2[i].pop(); 103 } 104 build(1,zz,1); 105 q1[ma[0]].push(0); 106 ch(ma[0],1,0); 107 for(int i=1;i<=L;i++) F[i]=-1e7; 108 for(register int i=L;i<=n;++i) 109 { 110 F[i]=max(max(get(1,ma[sum[i]]-1,1)+1,get(ma[sum[i]],ma[sum[i]],1)),get(ma[sum[i]]+1,zz,1)-1); 111 if(F[i]>n||F[i]<-n) F[i]=-1e7; 112 if(i-L+1>=0&&F[i-L+1]!=-1e7) 113 { 114 int tmp=ma[sum[i-L+1]]; 115 116 q1[tmp].push(F[i-L+1]); 117 118 while(!q1[tmp].empty()&&!q2[tmp].empty()&&q1[tmp].top()==q2[tmp].top()) q1[tmp].pop(),q2[tmp].pop(); 119 ch(tmp,1,q1[tmp].top()); 120 } 121 if(i-R>=0&&F[i-R]!=-1e7) 122 { 123 int tmp=ma[sum[i-R]]; 124 q2[tmp].push(F[i-R]); 125 126 while(!q1[tmp].empty()&&!q2[tmp].empty()&&q1[tmp].top()==q2[tmp].top()) q1[tmp].pop(),q2[tmp].pop(); 127 if(q1[tmp].empty()) ch(tmp,1,-1e7); 128 else ch(tmp,1,q1[tmp].top()); 129 } 130 } 131 printf("%d\n",F[n]); 132 } 133 return 0; 134 } 135 /* 136 1 137 5 1 1 138 1 -1 0 -1 1 139 */