小阳买水果
题目描述
水果店里有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;
}