100200F Think Positive

传送门

题目大意

给你一个数n和长度为n的序列,序列中的每个数均为1或-1,如果一个点j对于任意的k都满足题目中给的式子,则j是一个合法位置,问这样的j有多少个

分析

这道题有两种方法,分别对应代码1和代码2。

方法1

我们发现最终答案实际就是这n个数的和与0去最大值,因为我们不难发现对于任意两个相邻的1和-1它们的存在是没有意义的,因为这两个位置肯定不合法,而它们的和为0,对其它位置没有影响。所以在得到这些后我们只需把相邻的1和-1不断删掉就行了,因此可以证明之前的猜想。

方法2

我们发现对于每个j对应的最坏情况的k只有图1和图2两种情况,所以只要这两种情况满足且j的后缀大于0这个j就是合法的。

图1图2

这里的maxsur和minpre都是对于k的取值范围内的min或max,这就不由让我们想起了单调队列。我们根据sur和pre各建一个单调队列,然后用数组记录某个点是否两种情况均满足就可以了,注意在计算时的顺序问题,详见代码。

代码1

#include<bits/stdc++.h>
using namespace std;
int main(){
      freopen("positive.in","r",stdin);
      freopen("positive.out","w",stdout);
      int n,i,ans=0;
      cin>>n;
      for(i=1;i<=n;i++){
        int x;
          cin>>x;
          ans+=x;
      }
      if(ans>=0)cout<<ans<<endl;
          else cout<<0<<endl;
      return 0;
}

代码2

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
int pre[200100],sur[200100],qp[200100],qs[200100],lp,rp,ls,rs,a[200100];
int p1[200100],p2[200100],is[200100];
inline void init(){
      memset(pre,0,sizeof(pre));
      memset(sur,0,sizeof(sur));
      memset(qp,0,sizeof(qp));
      memset(qs,0,sizeof(qs));
      memset(is,0,sizeof(is));
      lp=ls=1;
      rp=rs=0;
}
int main(){
      freopen("positive.in","r",stdin);
      freopen("positive.out","w",stdout);
      int n,i,ans=0;
      init();
      scanf("%d",&n);
      for(i=1;i<=n;i++){
          scanf("%d",&a[i]);
          pre[i]=pre[i-1]+a[i];
      }
      for(i=n;i>0;i--)sur[i]=sur[i+1]+a[i];
      for(i=n;i>0;i--){
          while(pre[i]<qp[rp]&&rp>0){
            rp--;
          }
          qp[++rp]=pre[i];
          p1[rp]=i;
      }
      for(i=1;i<=n;i++){
          while(sur[i]>qs[rs]&&rs>0){
            rs--;
          }
          qs[++rs]=sur[i];
          p2[rs]=i;
      }
      for(i=1;i<=n;i++){
          while(p2[ls]<=i&&ls<=rs)ls++;
          if(ls>rs){
            if(sur[i]>0)is[i]++;
            continue;
          }
          if(sur[i]-qs[ls]>0)is[i]++;
      }
      for(i=n;i>0;i--){
          while(p1[lp]>=i&&lp<=rp)lp++;
          if(lp>rp){
            if(sur[i]>0)is[i]++;
            continue;
          }
          if(sur[i]+qp[lp]>0)is[i]++;
      }
      for(i=1;i<=n;i++)
        if(sur[i]>0&&is[i]==2)
          ans++;
      cout<<ans<<endl;
      return 0;
}
posted @ 2018-08-01 10:50  水题收割者  阅读(201)  评论(0编辑  收藏  举报