1. 程式人生 > 實用技巧 >2020 hdu多校賽 第八場 1002 Breaking Down News

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 */
View Code