【NKOJ3545】单调队列
单调队列是也。
NKOJ3545
我们发现,本题的时间复杂度必须是线性的,时间复杂度只能是 O(NT)
于是我们考虑如果如果原函数是单调的,前缀和也是单调的,那么本题就很好搞了。
在这种特殊情况下,我们利用单调队列,一个指向开头一个指向末尾。
由于sum[r]-sum[l]>=p时,向右移动r不会对答案进行更新
由于sum[r]-sum[l]<p时,向右移动l不会对答案更新,那么这个就很好,显然满足单调队列,那么我们就一直将R右移将L右移,始终满足sum[r]-sum[l]>=p (当sum[r]-sum[l+1]<p特判一下)
可是原数列中有负数怎么搞?不满足单调性啊啊啊?
我们开个结构体,将前缀和排个序就可以满足单调性了呀!
code:
#include<stdio.h> #include<bits/stdc++.h> #define int long long using namespace std; struct node { int sum,x; }z[100005]; int t; int n; int X; bool cmp(node aa,node bb) { return aa.sum<bb.sum; } int ansl,ansr,ans,L; int anz; void change(int l,int r) { int zhi = z[r].sum - z[l].sum ; int L = min(z[l].x,z[r].x); int R=max(z[l].x,z[r].x); L++; if(abs(X-zhi)>ans) return ; if(abs(X-zhi)==ans) { if(L<ansl) { ansl = L; ansr = R; anz =zhi; } else if(L==ansl&&R<ansr) { ansr = R; anz = zhi; } return; } ans = abs(X-zhi); ansl = L; ansr = R; anz = zhi; } void solve() { ans = 0x3f3f3f3f; L = 1; for(int i=2;i<=n;i++) { while( L<i-1&&z[i].sum-z[L+1].sum-X>=0 ) change(L,i),++L; if(L<i-1) change(L+1,i); change(L,i); } change(L,n); printf("%lld %lld %lld\n",anz,ansl,ansr); } main() { scanf("%lld%lld",&n,&t); for(int i=1;i<=n;i++) { scanf("%lld",&z[i].sum); z[i].sum = z[i-1].sum+z[i].sum; z[i].x = i; } z[++n].x = 0; z[n].sum = 0; sort(z+1,z+1+n,cmp); for(int i=1;i<=t;i++) scanf("%lld",&X),solve(); }