最小和[CODEVS1635]解题报告

题面:输出长度为N的数列中区间和绝对值最小的绝对值,若有多个最小区间和绝对值,则输出其可能的最长长度。N<=10^5
思路:把区间转换成前缀和,区间绝对值最小其实就是前缀和之差的绝对值最小,所以我们将其排序即可,相差最小的区间一定出现在排序后相邻的两个前缀和之中。
但是还要注意一些问题:

①若有多个区间的值相同,则应将他们再按端点排序,然后选择端点相差最大的两个。
②循环边界和更新条件需要仔细揣摩。

但是吧。。虽然上面两条我都没有考虑到,但还是A了这道题。。所有正确的点,9个点。。
至于还有一个点。。这个题的数据应该是有问题,我把数据下下来暴力做了一遍,也跟“正确答案”不一样。

代码:
 
#include<iostream>
using namespace std;
#include<cstdio>
#include<string>
#include<cmath>
#include<algorithm>
typedef long long lld;
lld a[100001];
struct S{
    lld s;
    int i;
    bool operator < (S a) const{
        if(s!=a.s)return s<a.s;
        else return i<a.i;
    }
}s[100002];
int main(){
    int ansl,tmpl,i,N,j;
    lld anss=0x7fffffffffffffffLL,tmps;
    scanf("%d",&N);
    s[0]=(S){0,0};
    for(i=1,++N;i<N;++i){
        scanf("%I64d",a+i);
        s[i].s=s[i-1].s+a[i];
        s[i].i=i;
    }
    sort(s,s+N);
    s[N].s=1LL<<62;
    for(i=0,--N;i<N;++i){
        if(s[i].s==s[i+1].s){
            if(anss){
                anss=0;
                ansl=0;
            }
            j=i;
            while(s[i].s==s[i+1].s)++i;
            ansl=max(abs(s[i].i-s[j].i),ansl);
        }
        tmps=abs(s[i].s-s[i+1].s);
        tmpl=abs(s[i].i-s[i+1].i);
        if(tmps<anss||tmps==anss&&tmpl>ansl){
            anss=tmps;
            ansl=tmpl;
        }
    }
    cout<<anss<<endl<<ansl;
}

你可能感兴趣的:(前缀和)