题意:询问一个静态序列的连续区间和绝对值最接近t的下标。
分析:由于询问的是绝对值,可以用前缀和相减得到区间和,并且和位置前后没有关系。于是把记录下标信息以后把
前缀和排序枚举大的前缀pj,pj-pi ≈ t,满足条件的:有pj-t的plower_bound以及plower_bound-1。
而pj-t也是单调的,再用一个下标i去维护就好。
/********************************************************* * ------------------ * * author AbyssalFish * **********************************************************/ #include<cstdio> #include<iostream> #include<string> #include<cstring> #include<queue> #include<vector> #include<stack> #include<vector> #include<map> #include<set> #include<algorithm> #include<cmath> #include<numeric> using namespace std; const int maxn = 1e5+1; int t, n, k; typedef pair<int,int> node; #define val first #define idx second node a[maxn]; int best, lb, ub; void update(int i,int j) { if(abs(a[j].val - a[i].val - t) < abs(best-t)){ best = a[j].val - a[i].val; lb = a[i].idx; ub = a[j].idx; } } void solve() { a[0].val = a[0].idx = 0; //空前缀是必要的 for(int i = 1; i <= n; i++) { a[i].val += a[i-1].val; a[i].idx = i; } sort(a,a+n+1); while(k--){ scanf("%d",&t); best = a[1].val-a[0].val, lb = a[1].idx, ub = a[0].idx; //(lb,ub] for(int i = 0, j = 1; j <= n; j++){ while(i < j && a[j].val - a[i].val > t) { //[i,j] i++; } if(i) update(i-1,j); if(i < j) update(i,j); } if(ub < lb) swap(ub, lb); printf("%d %d %d\n", best, lb+1, ub); } } //#define LOCAL int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif while(scanf("%d%d",&n,&k),n){ for(int i = 1; i <= n; i++){ scanf("%d",&a[i].val); } solve(); } return 0; }
时间: 2024-10-05 03:52:50