题目链接:http://codeforces.com/contest/1141/problem/F2
题意:现在有一个数列A,你需要选择一个sum,然后在序列中选择一些不重合的区间,区间和是sum,并且要区间的数目最多,问最多选择多少个区间,并将区间打印出来。
解题心得:
- 首先要明白,当起点相同的时候,得到相同的区间和,那么肯定是区间越短越好。
- 现在假设数组dp[i][j],意义为在前i个数中,和为j的区间最多有多少个。但是算一算空间太大(nnm),由1贪心可知,可以直接记录和为j的数在前i个中最后一个数的位置(区间一定是最短的),然后只要在j后面找到一个区间和为j那就可以直接加1。在寻找的时候可以直接用前缀和。
- 以为数字比较离散,用map映射会好一些.
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1510;
map <int, int> cnt;//记录和为first的值有second个
map <int, int> pos;//记录和为first的区间最后一个区间结束的位置为second
int sum[maxn], num[maxn], n;//记录前缀和,数列
void init() {
scanf("%d", &n);
for(int i=1;i<=n;i++) {
scanf("%d", &num[i]);
sum[i] = sum[i-1] + num[i];
}
}
int main() {
// freopen("1.in", "r", stdin);
init();
for(int i=1;i<=n;i++) {
for(int j=i-1;j>=0;j--) {
int va = sum[i] - sum[j];
if(pos[va] <= j) {
cnt[va]++;
pos[va] = i;
}
}
}
int va = -1;
map <int,int> :: iterator iter;
for(iter=cnt.begin();iter!=cnt.end();iter++) {
if(iter->second > cnt[va]) {
va = iter->first;
}
}
int pre = 0;
printf("%d\n", cnt[va]);
for(int i=1;i<=n;i++) {
for(int j=i-1;j>=pre;j--) {
if(sum[i] - sum[j] == va) {
pre = i;
printf("%d %d\n", j+1, i);
}
}
}
return 0;
}