
上下界:从数列中找出连续序列,使得和的绝对值与目标数之差最小。
3.2常用技巧精选(一)
尺取法
因为前缀和不单调,所以需要先排个序。之后就是尺取法了:首尾分别逐步向前挪动,挪动过程中记录答案。找了半天尺取虫的图片,还是卡通的容易接受一点,其他太惊悚
。另外以后ACM相关的文章放到算法分类下,不在放到C++里了。
#include <iostream>
#include <algorithm>
using namespace std;
#define MAX_N 100000 + 16
int a[MAX_N];
pair<int, int> accumulation[MAX_N]; // sum <-> index
// 更新答案
int get_sum(int& result, const int& l, const int& r, const int& t, int& from, int& to)
{
if (l >= r)
{
return INT_MIN; // 不合法,终止
}
int sum = accumulation[r].first - accumulation[l].first;
if (abs(t - sum) < abs(t - result)) // 顺便记录一下可能的答案
{
result = sum;
from = min(accumulation[l].second, accumulation[r].second);
to = max(accumulation[l].second, accumulation[r].second);
}
return sum;
}
///////////////////////////SubMain//////////////////////////////////
int main(int argc, char *argv[])
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
int n, k;
while (cin >> n >> k && n)
{
for (int i = 0; i < n; ++i)
{
cin >> a[i];
}
accumulation[0] = make_pair(0, 0); // 多留一个,待会儿免得下标跟答案对不上
for (int i = 0; i < n; ++i)
{
accumulation[i + 1] = make_pair(accumulation[i].first + a[i], i + 1);
}
sort(accumulation, accumulation + n + 1);
while (k--)
{
int t;
cin >> t;
// 输入结束
int l = 0, r = 0, sum = 0x80808080, from, to, result = 0x80808080;
for (;;)
{
while (r < n && sum < t)
{
sum = get_sum(result, l, ++r, t, from, to); // ++r 头部前进
}
if (sum < t)
{
break;
}
sum = get_sum(result, ++l, r, t, from, to); // ++l 尾部前进
}
cout << result << ' ' << from + 1 << ' ' << to << endl;
}
}
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
system("out.txt");
#endif
return 0;
}
///////////////////////////End Sub//////////////////////////////////
| 12873335 | hankcs | 2566 | Accepted | 1420K | 266MS | C++ | 1731B | 2014-05-14 01:53:02 |
知识共享署名-非商业性使用-相同方式共享:码农场 » POJ 2566 Bound Found 题解 《挑战程序设计竞赛》
码农场