题意:给定n个数,m次询问,每次询问一个数k,求n个数内所有区间的区间和的绝对值,最接近k的那个(非空)区间的和的绝对值,输出该区间的和的绝对值和左右端点。
思路:很有趣的一个尺取法的题,先转化成求出所有的前缀和,然后排序,任意一个不包含1端点的区间,都可以用两个区间的前缀和的差表示。要加入含1端点的区间,即前缀的情况,要么特别判断,
也可以加入一组0点的值0,
感想 :很难受,没有注意到区间为0的情况,初始复制一直将l=r=1;....WA+10+。。。贼尴尬,调了一晚上。。。都没有发现。最后跟着题解一点点分析,才发现的,,,
代码1:(自己的,但是加入包含1点的区间情况特判,但显得有点蠢,,)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;///!!!不能是空集
ll n,m,k,a[100005],l,r,s,ans,ansk,ansl,ansr;
struct AA
{
ll sum,r;
bool operator<(const AA &aa)const
{
return sum<aa.sum;
}
}pos[100010];
int main()
{
pos[0].sum=0;
pos[0].r=0;
while(scanf("%lld%lld",&n,&m))
{
if(n==0&&m==0) break;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]),pos[i].sum=pos[i-1].sum+a[i],pos[i].r=i;
}
sort(pos+1,pos+1+n);
while(m--)
{
scanf("%lld",&k);
l=1;r=2,ansk=99999999999;
while(1)
{
if(abs(abs(pos[l].sum)-k)<ansk)
{
ans=abs(pos[l].sum);
ansk=abs(ans-k);
ansl=0;
ansr=pos[l].r;
}
for(;r<=n;r++)
{
if(abs(pos[r].sum-pos[l].sum-k)<ansk)
{
ans=abs(pos[r].sum-pos[l].sum);
ansk=abs(ans-k);
ansl=pos[r].r;
ansr=pos[l].r;
}
if(pos[r].sum-pos[l].sum>k)
{
break;
}
}
l++;
if(l==r) r++;
if(l>n) break;
}
if(ansl>ansr) swap(ansl,ansr);
printf("%lld %lld %lld\n",ans,ansl+1,ansr);
}
}
}
代码2:(网上找的题解,但是加入1的方法,就是通过加一个0点,代码显得很简洁,整齐,优秀~)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int MAXN=1e5+5;
const int INF=2147483640;
pair<int,int> sum[MAXN];
int n,k,t;
void init()
{
sum[0]=make_pair(0,0);
int tmp=0;
for (int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
tmp+=x;
sum[i]=make_pair(tmp,i);
}
sort(sum,sum+n+1);
}
void solve()
{
scanf("%d",&t);
int l=0,r=1,minans=INF,ans,ansl,ansr;
while (r<=n && minans)//这里一开始写成了ans,以后变量名不要取那么相像orz
{
int delta=sum[r].first-sum[l].first;
if (abs(delta-t)<=minans)
{
minans=abs(delta-t);
ans=delta;
ansl=sum[l].second;
ansr=sum[r].second;
}
if (delta<t) r++;
if (delta>t) l++;
if (l==r) r++;//☆注意序列不能为空!
}
if (ansl>ansr) swap(ansl,ansr);//注意排序后是无序的,左右区间要调整回有序
printf("%d %d %d\n",ans,ansl+1,ansr);
}
int main()
{
while (scanf("%d%d",&n,&k)!=EOF)
{
init();
for (int i=1;i<=k;i++) solve();
}
return 0;
}