Bound Found
Time Limit: 5000MS | Memory Limit: 65536K | |||
Total Submissions: 2277 | Accepted: 703 | 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
题意:给你n个数字,这些数字可正可负,再给你个数字t,求在这个数列中一个连续的子序列,和的绝对值与t相差最小
错因分析:刚开始看到这道题目觉得很变态,尺取法怎么可能做得出来,这些数字是可正可负的,,后来看了题解,才恍然大悟,正因为是可正可负所以不能直接用尺取法去解题(尺取法必须是找到单调性),需要进行转化,找到单调性,但是a[i]数组是不能改变的,因为要求连续,那么就自然想到对a[i]求前缀和
先贴上别人好的代码,核心思想:对sum进行从小到大的排序,注意需要加入<0,0>这点(为了求得单独的sum,就是从第一个节点到sum[i]对应的i节点),然后尺取法设置左右两个端点,直接在sum数组上进行尺取法,需要注意的是对两个端点移动的判断,假设得出的int temp=p[r].first - p[l].first<k,说明temp偏小,那么r端点右移,否则>k的话,说明temp偏大,需要l端点右移,但是需要注意不能出现l==r的情况,因为序列不能为空,l==r,则序列为空;还有一点很重要的是因为求得是和的绝对值,即|sum[j]-sum[i]|,那么只需要对sum数组进行从小到大排序,用大的减去小的就可以了(这也是去绝对值的体现)
#include<cstdio> #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <queue> #include<map> #include <algorithm> #include <set> using namespace std; #define MM(a) memset(a,0,sizeof(a)) typedef long long LL; typedef unsigned long long ULL; const int mod = 1000000007; const double eps = 1e-10; const int inf = 0x3f3f3f3f; pair<int, int > p[100005]; int n, m, k; void solve(int k) { int l = 0, r = 1, al, ar, av, minn = inf; while (l<=n&&r<=n&&minn!=0) { int temp=p[r].first - p[l].first; if (abs(temp - k) < minn) { minn = abs(temp - k); ar = p[r].second; al = p[l].second; av = temp; } if (temp> k) l++; else if (temp < k) r++; else break; if (r == l) r++; } if(al>ar) swap(al,ar);//因为al和ar大小没有必然关系()取绝对值,所以//要交换 printf("%d %d %d\n", av, al+1, ar); } int main() { while (~scanf("%d %d", &n, &m)) { if (!n&&!m) return 0; p[0] = make_pair(0, 0); for (int i = 1; i <= n; i++) { scanf("%d", &p[i].first); p[i].first += p[i - 1].first; p[i].second = i; } sort(p, p + n + 1); while (m--) { scanf("%d", &k); solve(k); } } return 0; }
下面是自己的wa代码
好好找茬
#include<cstdio> #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <queue> #include<map> #include <algorithm> #include <set> using namespace std; #define MM(a) memset(a,0,sizeof(a)) typedef long long LL; typedef unsigned long long ULL; const int mod = 1000000007; const double eps = 1e-10; const int inf = 0x3f3f3f3f; pair<int, int > p[100005]; int n, m, k; void solve(int k) { int l = 0, r = 1, al, ar, av, minn = inf; while (l<=n&&r<=n) { int temp = p[r].first - p[l].first; if (abs(temp - k) < minn) { minn = abs(temp - k); ar = p[r].second; al = p[l].second; av = temp; } if (temp > k) l++; else if (temp < k) r++; else break; if (r == l) r++; } printf("%d %d %d\n", av, al+1, ar); } int main() { while (~scanf("%d %d", &n, &m)) { if (!n&&!m) return 0; p[0] = make_pair(0, 0); for (int i = 1; i <= n; i++) { scanf("%d", &p[i].first); p[i].first += p[i - 1].first; p[i].second = i; } sort(p + 1, p + n + 1); while (m--) { scanf("%d", &k); solve(k); } } return 0; }