POJ2566 前缀和优化,快慢指针

一开始没有用前缀和处理,发现如果数据里带负数的话,快慢指针的移动判定条件不好写。如果暴力枚举起点的话,那么和暴力的o(n^2)没有任何本质区别。后面发现可以用前缀和进行优化,这样子的话就可以到了一个o(n)的级别(区间i,j和=j前缀和-i前缀和),因此只要判断当前区间和与记录答案进行比较就可以了。

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
#define inf 0x3f3f3f3f
const int maxn = 500010;
using namespace std;
int a[maxn];
struct node{
    
    
    int presum,id;
}p[maxn];
int n,m;
int sum;
bool cmp(node a,node b)
{
    
    
    return a.presum < b.presum;
}
void Find(int tar){
    
    
    int p1 = 0,p2 = 1,ans = inf,left,right,val,tmp;
    while(p2 <= n && ans)
    {
    
    
        tmp = p[p2].presum - p[p1].presum;
        if(abs(tmp - tar) < ans)
        {
    
    
            ans = abs(tmp - tar);
            val = tmp;
            left = p[p1].id;
            right = p[p2].id;
        }
        if(tmp < tar)p2++;
        if(tmp > tar)p1++;
        if(p1 == p2)p2++;
    }
    if(left > right)
        swap(left,right);
    cout<<val<<" "<<left+1<<" "<<right<<endl;
}
int main()
{
    
    
    while(~scanf("%d%d",&n,&m)&&n&&m)
    {
    
    
        sum = 0;
        p[0].presum = 0,p[0].id = 0;
        for(int i = 1;i <= n;i++){
    
    
            scanf("%d",&a[i]);
            sum += a[i];
            p[i].presum = sum;
            p[i].id = i;
        }
        sort(p,p+n+1,cmp);
        while(m--)
        {
    
    
            int tar;
            scanf("%d",&tar);
            Find(tar);
        }
    }
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42937838/article/details/108981340