http://codeforces.com/contest/808/problem/D
一开始是没什么想法的,然后回顾下自己想题的思路,慢慢就想出来了。首先要找到是否有这样的一个位置使得:
前缀和 == 后缀和,可以二分来求。
然后可以这样想,如果对于每一个数字,我都去移动一下,每个位置都试一下,复杂度多少?显然不能承受。
然后优化下这个思路,有了一点思路,优化到极致,看看能不能过,不能过就换思路吧。一般来说,每一个位置都试一下,是很没必要的。一般都是有一个位置是最优的。
这个位置就是放在最前或者放在最后。可以这样去想。
如果原来的数组,是不存在这样的位置的,那么移动a[i]到某一个位置后,存在了这样的位置。那么肯定是把这个数字移动去了前缀和的贡献哪里(后缀和同理),因为不是移动到前缀和哪里,就相当于没移。
所以把它移动到第1位,前缀和就肯定包含它了。
最后还是被hack,细节写歪了
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;
#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <bitset>
const int maxn = 1000000 + 20;
int n;
int a[maxn];
LL sum[maxn];
LL nowDel;
LL ask(int pos) {
if (pos < nowDel) {
return sum[pos] - a[pos] + a[nowDel];
} else return sum[pos];
}
LL ask2(int pos) {
if (pos >= nowDel) {
return sum[pos] - a[nowDel] + a[pos + 1];
} else return sum[pos];
}
bool tofind(int which) {
int be = 2, en = n;
while (be <= en) {
int mid = (be + en) >> 1;
LL lef;
if (which == 1) lef = ask(mid - 1);
else lef = ask2(mid - 1);
LL rig = sum[n] - lef;
if (lef < rig) be = mid + 1;
else en = mid - 1;
}
LL lef;
if (which == 1) lef = ask(en);
else lef = ask2(en);
return lef * 2 == sum[n];
}
void work() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
sum[i] = sum[i - 1] + a[i];
}
// nowDel = 2;
// tofind(2);
for (int i = 1; i <= n; ++i) {
nowDel = i;
if (tofind(1)) {
printf("YES\n");
return;
}
if (tofind(2)) {
printf("YES\n");
return;
}
}
printf("NO\n");
}
int main() {
#ifdef local
freopen("data.txt", "r", stdin);
// freopen("data.txt", "w", stdout);
#endif
work();
return 0;
}
View Code