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

 

posted @ 2020-08-13 21:07  Hzoi_joker  阅读(252)  评论(0编辑  收藏  举报