P3503 [POI2010]KLO-Blocks
题目描述
思路
答案是一段连续的区间,而且这个区间满足平均数>=k。
将所有数减去k,则这个区间和>=0。
再求个前缀和,则s[r]>=s[l-1]。
也就是对每个s[r],我们要求满足s[l]<=s[r]的最小的l。
如果s[r]>=s[l],那么r永远不会是右边的选择,所以可以扔掉。
维护一个单调递减的栈。
查询时二分最左的<=s[r]的s[l]。
时间nlogn。
这个建栈和查询是可以分开的。
如果s[r]>=s[l],l的选择永远可以被r选择,而且会更优,所以l永远不用查询了。
所以可查询的数也可以建一个单调递减的栈。
随着s[r]递增,l是单调左移的,于是就可以O(n)了。
代码
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int N=1000010; int m,k,i; int q1[N],q2[N]; int a[N],n,t1,t2; long long sum[N],now; int main () { scanf("%d%d",&n,&m); for(i=1; i<=n; i++) scanf("%d",&a[i]); sum[q1[0]=q2[0]=N-1]=1e18; while(m--) { scanf("%d",&k); for(i=1; i<=n; i++) sum[i]=sum[i-1]+a[i]-k; t1=1,t2=0; for(i=1; i<=n; i++) { now=sum[i]; if(now<sum[q1[t1]]) q1[++t1]=i; while(now>=sum[q2[t2]]) t2--; q2[++t2]=i; } int ans=0; for(; t2; --t2) { now=sum[i=q2[t2]]; if(now<sum[q1[t1]]) continue; while(now>=sum[q1[t1]]) --t1; ans=max(ans,i-q1[t1+1]); } printf("%d ",ans); } return 0; }