题面描述:
美国航空航天局(该机构似乎正经历叛逆期:"我就要用英尺,才不用米呢!")接收并数字化了极可能来自地外文明的信号。每个信号包含两部分:一个由n个整数值组成的序列和一个非负整数t。虽然细节不便透露,但研究人员发现信号编码了两个整数值。这两个值可以表示为序列某个子区间的下界和上界,该子区间和的绝对值最接近t。
现在给定包含n个整数的序列和非负目标值t。你需要找出序列的一个非空区间(即连续子序列),输出其起始索引l和终止索引u。要求从第l个到第u个元素(包含两端)的序列值之和的绝对值,必须比其他任何非空区间和的绝对值更接近t。
输入格式:
输入文件包含多个测试用例。每个测试用例以两个数字n和k开始。当n=k=0时输入终止。否则满足¥1≤n≤100000,随后给出构成序列的n个绝对值不超过10000的整数。接着是k个针对该序列的查询,每个查询给出一个目标值t(0≤t≤1000000000)。
输出格式:
对于每个查询,输出一行包含3个数字:最接近的绝对和值,以及实现该绝对和的某个区间的起始和终止索引。索引从1开始计数,最大不超过n。
样例:
INPUT | OUTPUT |
---|---|
5 1 -10 -5 0 5 10 3 10 2 -9 8 -7 6 -5 4 -3 2 -1 0 5 11 15 2 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 15 100 0 0 |
5 4 4 5 2 8 9 1 1 15 1 15 15 1 15 |
题解:
先记录数组前缀和 \(d_i\) 并将其升序排序构造单调性,使用双指针 l , r 枚举左右前缀和数组,如大于 t 则 r++ ,小于 t 则 l++ , 等于则直接Break,注意 \(d_l.id\) 与 \(d_r.id\) 为乱序,先输出小的再输出大的。
神秘样例过不了qwq
AC CODE:
#include<iostream>
#include<algorithm>
#include<cstring>
#define int long long
using namespace std;
const int N=1e5+10;
struct node{int val,id;
}d[N];
int n,k,a[N];
bool cmp(node x,node y){return x.val<y.val;
}
signed main(){while(true){memset(d,0,sizeof(d));for(int i=1;i<=n;i++) d[i].val=0;cin>>n>>k;if(n==0&&k==0) break;for(int i=1;i<=n;i++) cin>>a[i];for(int i=1;i<=n;i++) d[i].val=d[i-1].val+a[i],d[i].id=i;sort(d,d+n+1,cmp);for(int i=1;i<=k;i++){int t;cin>>t;int minn=1e18,l=0,r=1,ansl,ansr,ans;while(r<=n){int num=d[r].val-d[l].val;//cout<<l<<" "<<r<<" "<<d[l].val<<" "<<d[r].val<<endl;if(abs(num-t)<minn) minn=abs(num-t),ans=num,ansl=d[l].id,ansr=d[r].id;if(num<t) r++;else if(num>t) l++;else break;if(l==r) r++;}if(ansl>ansr) swap(ansl,ansr);cout<<ans<<" "<<ansl+1<<" "<<ansr<<endl;}} return 0;
}