P3768 数列操作
问题描述
给出 N 个正整数数列 a[1..N],再给出一个正整数 k,现在可以重复进行如下操作:
每次选择一个大于 k 的正整数 a[i],将 a[i]减去 1,选择 a[i-1]或 a[i+1]中的一个加上 1。
经过一定次数的操作后,问最大能够选出多长的一个连续子序列,使得这个子序列的每个数都不小于 k。
总共给出 M 次询问,每次询问给出的 k 不同,你需要分别回答。。
输入格式
第一行两个正整数 N 和 M 。
第二行 N 个正整数,第 i 个正整数表示 a[i] 。
第三行 M 个正整数,第 i 个正整数表示第 i 次询问的 k 。
输出格式
共一行,输出 M 个正整数,第 i 个数表示第 i 次询问的答案。
输入输出样例
样例输入 1
5 6
1 2 1 1 5
1 2 3 4 5 6
样例输出 1
5 5 2 1 1 0
样例输入 2
6 4
3 2 1 2 5 1
3 4 1 6
样例输出 2
2 1 6 0
数据范围
对于 40%的数据, 1<=N<=100 1<=M<=50
对于 100%的数据,1<=N<=300000 1<=M<=50a[i] <= 10^9 k <= 10^9
题目当中的操作其实可以转化为:
对于区间[l,r],若sum[l,r]>=(r-l+1)*k,则该区间满足要求 操作后每个数字不小于k
其实我们算的是 sum[l,r] - (r-l+1)*k 是否大于0
但是对于不同的区间[l,r],减去的(r-l+1)*k是不同的 这就很难处理了
对于区间[1,n] 求出最长的子区间[l,r] 满足sum[l,r]>=0
这道题目就简单多了
①求出前缀和的单调递减序列
②求出满足sum[1,r]-sum[1,l]>0的 r-l 最大值
例如 区间元素为 1 -2 1 1 -4 1 2
那么前缀和为 1 -1 0 1 -3 -2 0
单调递减序列 0(pos=0) -1 -3
于是在求r-l的最大值时 我们就枚举pos=7 -> pos=1
求出对于r 最小的单调序列的编号
pos=7时 单调队列的当前编号为5,对应的前缀和为-3
sum[7] - sum[5] = 0(第七个位置的前缀和)-(-3)(第五个位置的前缀和)=3>0
所以可以更新最大长度为 7-5+1=3
如此往复 即可得到对于7的最长序列为 7(pos=0的点sum=0->满足条件)
为什么我们只需要考虑单调队列中的元素呢?
对于单调队列中的任意两个连续的下标 l,r 当天讨论的点为 p
如果 sum[p]-sum[l]<0
那么由于队列的单调性 sum[p+k]>=sum[p] (p+k=sum[p]所以sum[p+k]也一定不满足要求
反之 如果sum[p+k]满足要求 那么sum[p]也一定能满足要求
答案是肯定的
我们可以把数列中的每一个数字都减去 k
转化后 我们求得等价于原来的
sum[l,r] -(r-l+1)k >= (r-l+1)k -(r-l+1)k
[黑色的字体即为减去的k们]
①要用long long(套路真的深)
②对于最长的满足要求的序列即为原序列的特殊情况,我们应该把队列中的第一个元素位置赋值为0 sum[0]=0 (具体原因自己想想 当然你也可以先WA再想)
#include
#include
using namespace std;
inline long long input()
{
char c=getchar();long long o;
while(c>57||c<48)c=getchar();
for(o=0;c>47&&c<58;c=getchar())o=(o<<1)+(o<<3)+c-48;
return o;
}
long long n,m,res,k,top;
long long a[300123],sum[300123],sq[300123];
int main()
{
// freopen("sequence.in","r",stdin);
// freopen("sequence.out","w",stdout);
n=input();m=input();
for(long long i=1;i<=n;i++)a[i]=input();
for(long long t=1;t<=m;t++)
{
k=input();res=0;top=1;
for(long long i=1;i<=n;i++)
{
sum[i]=sum[i-1]+a[i]-k;
if(sum[i]sq[top]])sq[++top]=i;
}
for(long long i=n;i;i--)
{
while(top&&sum[sq[top]]<=sum[i])top--;
res=max(res,i-sq[top+1]);
}
printf("%d ",res);
}
}