题目链接
题意
一整数数列 a1 a 1 , a2 a 2 , ⋯ ⋯ an a n (有正有负),以及另一个整数 k k ,求一个区间, 使得 ai+⋯+aj=k a i + ⋯ + a j = k 。其中 ai,k∈[−109,109] a i , k ∈ [ − 10 9 , 10 9 ] , N∈[2,104] N ∈ [ 2 , 10 4 ]
题解
我想说这题数据出得太水了,网上那些 O(n2) O ( n 2 ) 的做法都能过,还有用map 优化的,降到 O(nlogn) O ( n log n ) 也有点玄学,我觉得应该把 N N 取到 的,其实比较稳的 O(nlogn) O ( n log n ) 的解法还是很好想的。
用一个结构体存两个int,一个表示前缀和,一个表示当前所在位置,以前缀和为主关键字从小到大排序,然后放到set 里面find 就行了。
过题代码
#include <set>
#include <cstdio>
using namespace std;
#define LL long long
const int maxn = 10005;
struct Node {
LL sum;
int pos;
Node(LL s, int p) {
sum = s;
pos = p;
}
};
bool operator<(const Node &a, const Node &b) {
if(a.sum == b.sum) return a.pos < b.pos;
return a.sum < b.sum;
}
bool flag;
LL n, k;
LL num[maxn], sum[maxn];
set<Node> s;
set<Node>::iterator it;
int main() {
scanf("%lld%lld", &n, &k);
for(int i = 0; i < n; ++i) {
scanf("%lld", &num[i]);
sum[i + 1] = sum[i] + num[i];
s.insert(Node(sum[i + 1], i + 1));
}
for(int i = 0; i < n; ++i) {
it = s.lower_bound(Node(sum[i] + k, i + 1));
if(it->sum == sum[i] + k) {
flag = true;
printf("%d %d\n", i + 1, it->pos);
break;
}
}
if(!flag) {
printf("No Solution\n");
}
return 0;
}