描述


http://poj.org/problem?id=2566

给出一个整数序列,并给出非负整数t,求数列中连续区间和的绝对值最接近k的区间左右端点以及这个区间和的绝对值.

Bound Found
Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 2592   Accepted: 789   Special Judge

Description

Signals of most probably extra-terrestrial origin have been received and digitalized by The Aeronautic and Space Administration (that must be going through a defiant phase: "But I want to use feet, not meters!"). Each signal seems to come in two parts: a sequence of n integer values and a non-negative integer t. We'll not go into details, but researchers found out that a signal encodes two integer values. These can be found as the lower and upper bound of a subrange of the sequence whose absolute value of its sum is closest to t.

You are given the sequence of n integers and the non-negative target
t. You are to find a non-empty range of the sequence (i.e. a continuous
subsequence) and output its lower index l and its upper index u. The
absolute value of the sum of the values of the sequence from the l-th to
the u-th element (inclusive) must be at least as close to t as the
absolute value of the sum of any other non-empty range.

Input

The
input file contains several test cases. Each test case starts with two
numbers n and k. Input is terminated by n=k=0. Otherwise,
1<=n<=100000 and there follow n integers with absolute values
<=10000 which constitute the sequence. Then follow k queries for this
sequence. Each query is a target t with 0<=t<=1000000000.

Output

For
each query output 3 numbers on a line: some closest absolute sum and
the lower and upper indices of some range where this absolute sum is
achieved. Possible indices start with 1 and go up to n.

Sample Input

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

Sample Output

5 4 4
5 2 8
9 1 1
15 1 15
15 1 15

Source

分析


尺取法.

一眼看过去就是用尺取法找和t绝对值相差最小的区间和,但是这道题里的序列并不是非负的,这意味着固定左端点,移动右端点时,区间和不是单调递增的.尺取法的模板题中区间和是单调的,所以找到大于某一值的区间右端点就可以固定.而这道题中因为存在负值,所以区间的变化不是单调的,不能按照普通的方法解决.我们考虑一段区间和,不仅可以认为是a[l]+a[l+1]+...+a[r],还可以看作是sum[r]-sum[l-1],而这道题中要求的区间和的绝对值,就可以看作是max(sum[r],sum[l-1])-min(sum[r],sum[l-1]).这样求一个前缀和,进行排序,双指针确定区间左右端点,这样sum[r]-sum[l](排序后的编号)就代表一个区间和的绝对值,这样的区间就是单调的.如此一来,确定左端点,移动右端点,sum[r]-sum[l]就是单增的,找到sum[r]-sum[l]>t的位置即可停止,然后l++,sum[r-1]-sum[l]比之前的sum[r-1]-sum[l]更小(减数增大),本来就比t小,现在小得更多了,对于任意r'<=r-1都是如此,就不必考虑,从sum[r]-sum[l]开始继续即可.

注意:

1.sum[r]-sum[l-1],因为1<=l<=r,所以l-1>=0,注意sum[0].s=0,sum[0].num=0,要参与排序,并且每一次都要重新赋值,因为上一组数据排序后sum[0].s不一定是0,这将影响到语句"sum[i]=point(sum[i-1].s,i)" .

2.对于区间右端点表示的状态,最好是用来表示当前右端点的位置,然后每一次更新状态时都要判断,与ans比较,看是否更新最优解.

3.由于r>=l所以r>l-1,也就是说两个区间端点不能是同一个点,当l追上r时,r++.

4.其实尺取法的写法可以优化,现在的写法是两层循环,l改变后进行一次操作,然后对于同一个l改变r,每次进行一次操作,这样在一个外层循环内部要写两遍操作.其实对于l和r的改变是一样,都是区间状态的改变,所以只要一层循环即可.

  while (l<=n&&r<=n&&ans!=) 
 #include<cstdio>
#include<cstdlib>
#include<algorithm>
using std :: sort;
using std :: min;
using std :: max; const int maxn=,INF=0x7fffffff; int a[maxn],s[maxn];
int n,q,t; struct point
{
int s,num;
point() {}
point(int a,int b) : s(a) , num(b) {}
}sum[maxn]; bool comp(point x,point y) { return x.s<y.s; } int value(int l,int r) { return abs(sum[r].s-sum[l].s); } int L(int l,int r) { return min(sum[l].num,sum[r].num)+; } int R(int l,int r) { return max(sum[l].num,sum[r].num); } void solve(int t)
{
int ans=INF,res,idxl,idxr;
int r=;
for(int l=;l<=n;l++)
{
if(l==r) r++;
if(r>n) break;
int now=value(l,r);
int d=abs(now-t);
if(d<=ans)
{
ans=d;
res=now;
idxl=L(l,r);
idxr=R(l,r);
}
while(r<n&&now<t)
{
r++;
now=value(l,r);
int d=abs(now-t);
if(d<=ans)
{
ans=d;
res=now;
idxl=L(l,r);
idxr=R(l,r);
}
}
if(now<t) break;
if(now==t)
{
break;
}
}
printf("%d %d %d\n",res,idxl,idxr);
} void init()
{
while(scanf("%d%d",&n,&q)&&(n!=||q!=))
{
sum[].s=;
sum[].num=;
for(int i=;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i]=point(sum[i-].s+a[i],i);
}
sort(sum,sum+n+,comp);
for(int i=;i<=q;i++)
{
scanf("%d",&t);
solve(t);
}
}
} int main()
{
freopen("bound.in","r",stdin);
freopen("bound.out","w",stdout);
init();
fclose(stdin);
fclose(stdout);
return ;
}

POJ_2566_Bound_Found_(尺取法+前缀和)的更多相关文章

  1. POJ 3061 (二分+前缀和or尺取法)

    题目链接: http://poj.org/problem?id=3061 题目大意:找到最短的序列长度,使得序列元素和大于S. 解题思路: 两种思路. 一种是二分+前缀和.复杂度O(nlogn).有点 ...

  2. POJ 2566 Bound Found(尺取法,前缀和)

    Bound Found Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 5207   Accepted: 1667   Spe ...

  3. poj 2566Bound Found(前缀和,尺取法)

    http://poj.org/problem?id=2566: Bound Found Time Limit: 5000MS   Memory Limit: 65536K Total Submissi ...

  4. 题解报告:poj 3061 Subsequence(前缀+二分or尺取法)

    Description A sequence of N positive integers (10 < N < 100 000), each of them less than or eq ...

  5. hdu 5510 Bazinga KMP+尺取法

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5510 题意:至多50组数据,每组数据至多500个字符串,每个字符串的长度最长为2000.问最大的下标( ...

  6. POJ2566-Bound Found (尺取法)

    POJ2566-Bound Found 题目大意:给出一段长度为n的数列,数列中的元素有正有负,求一段连续的区间,使得该区间的和的绝对值最接近给定的值 尺取法一般适用于对一段连续的区间的和进行处理的情 ...

  7. NanoApe Loves Sequence Ⅱ(尺取法)

    题目链接:NanoApe Loves Sequence Ⅱ Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/131072 ...

  8. Bound Found [POJ2566] [尺取法]

    题意 给出一个整数列,求一段子序列之和最接近所给出的t.输出该段子序列之和及左右端点. Input The input file contains several test cases. Each t ...

  9. poj 2566"Bound Found"(尺取法)

    传送门 参考资料: [1]:http://www.voidcn.com/article/p-huucvank-dv.html 题意: 题意就是找一个连续的子区间,使它的和的绝对值最接近target. ...

随机推荐

  1. Jar mismatch! Fix your dependencies的问题(转)

    看到网上有说: 在开发Android项目的时候,有时需要引用多个项目作为library.在引用项目的时候,有时会出现“Jar mismatch! Fix your dependencies”错误. 这 ...

  2. [可拖动DIV]刚开通博客顺便就写了点东西!

    说说我自己的思路 首先需要一个初始div div { border: 1px #333 solid; width: 200px; height: 50px; } <div id="od ...

  3. 对WebClient扩展自动解压缩页面

    WebClient下载压缩网页时出现的全是乱码,可通过扩展来解决这个问题. public class MyWebClient : WebClient { protected override WebR ...

  4. 使用WebClient上传文件时的一些问题

    最近在使用WebClient做一个客户端上传图片到IIS虚拟目录的程序的时候,遇到了一些问题,这里主要给出参考步骤分享给大家. 测试环境 服务器端:Windows Server 2003,IIS6.0 ...

  5. IOS中如何自定义web应用的图标

    在iPhone/iPad等苹果移动设备上,可以把网站”添加至主屏幕”,添加时的图标可以在HTML中自定义设置图片. 可以使用apple-touch-icon和apple-touch-icon-prec ...

  6. 拓展:switch实现

    拓展:switch实现 参考中谷教育 python视频:switch  switch语句用于编写多分支结构的程序,类似于if ... elif ...else语句.switch语句表达的分支结构比if ...

  7. RS232转RS485电路图分析

    在电子发烧友网站上,看到RS232转RS485的一个电路图,如下图所示.元件主要是HN232CP和MAX485CPA,也就是TTL转232电路和TTL转485电路的结合体.可是这个电路却不好分析,几经 ...

  8. The partner transaction manager has disabled its support for remote/network transactions.

    http://technet.microsoft.com/en-us/library/cc753510(WS.10).aspx

  9. Cocos2dx坐标转换

    Cocos2dx坐标转换 这段时间加班有点猛,没有太多时间来写博客了,ok,继续完成任务: 前言 这里将会重点介绍四个函数: convertToNodeSpace convertToNodeSpace ...

  10. I2C总线模拟(郭天祥视屏)

    电路图 思路 1.向EEPROM中通过I2C总线写入一个字节 2.通过I2C总线读出写入的字节 3.如果写入和读出成功点亮发光二极管 程序 #include <REGX51.H> #def ...