小阳买水果

小阳买水果

题目描述

水果店里有n个水果排成一列。店长要求顾客只能买一段连续的水果。小阳对每个水果都有一个喜爱程度
ai,最终的满意度为他买到的水果的喜欢程度之和。如果和为正(不管是正多少,只要大于 0 即可),他就满意了。小阳想知道在他满意的条件下最多能买多少个水果。你能帮帮他吗?

输入描述:

第一行输入一个正整数 n,表示水果总数。

第二行输入 n 个整数 ai,表示小阳对每个水果的喜爱程度。

输出描述:

一行一个整数表示结果。(如果 1 个水果都买不了,请输出 0)

示例1

输入

5
0 0 -7 -6 1

输出

1

备注:

1≤n≤2×10 ^ 6,|ai|≤10 ^3

第一感觉是二分查找O(nlogn),但是看下面的例子:
3
1 -1 1
二分不行,题解也看不懂,太菜了。。。
发现,用结构体将前缀和和位置记录起来,按前缀和从大到小排序,相同位置也按从大到小排序,则从0到n(不是n-1)遍历,j用来记录已经遍历的位置最大的pos,若是遇到pos小的,说明符合条件,直接更新答案。
代码:

#include<bits/stdc++.h>
using namespace std;
char buf[1<<17],*L=buf,*R=buf;
inline char gc() {
   return L==R&&(R=(L=buf)+fread(buf,1,1<<17,stdin),L==R)?EOF:*L++;
}
template<typename T>
inline void read(T&x) {
   int flag=0;
   char ch=gc();x=0;
   while (ch<'0'||ch>'9') {if(ch=='-')flag=1;ch=gc();}
   while (ch>='0'&&ch<='9')x=x*10+ch-48,ch=gc();
   if(flag)x=-x;
}
const int MAXN=2e1+10;
struct Node{
   int sum,pos;//前缀和和位置
   bool operator<(const Node&b){
       if(sum==b.sum)return pos>b.pos;
       return sum>b.sum;
   }
}p[MAXN];
int n,x,ans;
int main() {
   read(n);
   for(int i=1;i<=n;++i){
       read(x);
       p[i].pos=i;
       p[i].sum=p[i-1].sum+x;
   }
   sort(p,p+n+1);//从0开始,未sort前p[0].pos=0 , p[0].sum=0,必须加上这么个东西,
   //因为sum[i,j]=sum[j]-sum[i-1]
   // 前n个的和sum[1,n]==sum[n]-sum[0];
   for(int i=0,j=0;i<=n;++i){//
       if(p[i].pos>p[j].pos)
           j=i;
       else if(p[j].sum>p[i].sum)//这不能用else 满意度要大于零才能符合条件,>也可以改成!=
           ans=max(ans,p[j].pos-p[i].pos);
   }
   cout<<ans;
   return 0;
}
原文地址:https://www.cnblogs.com/foursmonth/p/14144873.html