题目大意:给出一个序列,给出目标值k,求一个连续子序列,使得该子序列之和与k之差最小
分析:尺取法。首先,了解一下尺取法的题目有哪些特性。
一、连续性。所求序列是一个连续序列。
二、单调性。求解的序列满足某种单调性。
此题所求的序列明显满足第一个特性,但是,第二个特性并不能满足。
于是,我们可以联想到前缀和(暑假做题的过程中,慢慢发现前缀和是个好东西…0.0)。然后用pair,这样既可以得到单调性,又可以得到位置。
a[i]表示原数列中的值,b[i]表示原数列前i项和。对b[i]进行sort,然后就可以用尺取法啦~
代码:
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const int maxn = 100000+10; int a[maxn]; pair <int, int> b[maxn]; int ans, x, sum, et, es, s, t; int n, k, mid; int main() { while(scanf("%d%d", &n, &k) && n != 0) { b[0] = make_pair(0, 0); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); b[i] = make_pair(b[i-1].first+a[i], i); } sort(b, b+n+1); while(k--) { ans = 1 << 30; scanf("%d", &mid); x = 1 << 30; s = 0, t = 1; es = et = 0; while(t <= n && x) { int temp = b[t].first-b[s].first; if(abs(mid-temp) < x) { x = abs(mid-temp); ans = temp; es = b[s].second; et = b[t].second; } if(temp < mid) t++; else s++; if(s == t) t++; } printf("%d %d %d\n", ans, min(es, et)+1, max(es, et)); } } return 0; }