版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40924940/article/details/83548434
这道题仍然是一个尺取法 尺取法 需要整个数列具有单调性 (开始我一直以为单调性是单调递增或递减,然而并不是)
单调性就是 比如 区间取和 我在右边界向右延伸的过程中 整个区间和是不断增大的 不会变小 不然右侧就不会延伸 反而右边会向回收缩,这样的话就会造成一种很混乱的局面。
那么我们来看题目
本体题意:
一共N个数 给你K个数字 每个数字大小为 T 求一个区间使其区间和最接近T
输入 N K 然后输入 N个数字,最后输入K个 T
输出 区间和 区间左边界 右边界
(多组输入,n==k==0时结束)
因为这道题目 给的数字可能是 负数 如果还按照老的方法去算 可能会出现 r 向回收缩,l 向左延伸的现象,所以为了避免这种情况,我们可以引入前缀和,然后排序一下,这样不就可以保证 R 在向右的过程中 整个区间和是一直在增大的,L 收缩的过程中整个区间和是一直在减小的 ,成功实现尺取法
下方是AC代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;
const int maxn = 1e6+5;
const int inf = 0x3f3f3f3f;
int fabs(long long int x)
{
return x<0?-x:x;
}
struct node
{
long long int id,v;
}num[maxn];
bool cmp(node a,node b)
{
return a.v<b.v;
}
int n,t,k;
int l,r;
long long int a[maxn];
int main()
{
while(cin>>n>>k&&n+k!=0)
{
for(int i=0;i<=n;i++)
num[i].v=0,num[i].id=i;
for(int i=1;i<=n;i++)
{
cin>>a[i];
num[i].v=num[i-1].v+a[i];
}
sort(num,num+n+1,cmp);
while(k--)
{
cin>>t;
l=0,r=1;
long long int ll,rr,minn=inf,ans;
while(l<=n&&r<=n&&minn!=0)
{
long long int temp = num[r].v-num[l].v;
if(minn>fabs(t-temp))
{
minn=fabs(t-temp);
ll=num[l].id;
rr=num[r].id;
ans=temp;
}
if(temp > t)
l++;
else if(temp < t)
r++;
else break;
if(l==r)r++;
}
if(ll>rr) swap(ll,rr);
cout<<ans<<' '<<ll+1<<' '<<rr<<endl;
}
}
return 0;
}