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 "); return; } if (tofind(2)) { printf("YES "); return; } } printf("NO "); } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif work(); return 0; }