题目链接:http://codeforces.com/contest/808/problem/D
题意:有一串长度为n的数组,要求选择一个数字交换它的位置使得这串数能够分成两串连续的和一样的数组。
这个数还可以和自己交换位置。
题解:很显然求一下前缀二分每个数看一下能否插入,再求一下后缀二分每个数看一下能否插入。
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; typedef long long ll; const int M = 1e5 + 10; ll a[M] , be[M] , af[M]; bool binsearch(int l , int r , ll sum , ll gg[] , int pos) { int mid = (l + r) >> 1; while(l <= r) { mid = (l + r) >> 1; if(gg[mid] == sum) { if(pos == mid) return false; else return true; } if(gg[mid] > sum) r = mid - 1; if(gg[mid] < sum) l = mid + 1; } return false; } bool binsearch2(int l , int r , ll sum , ll gg[] , int pos) { int mid = (l + r) >> 1; while(l <= r) { mid = (l + r) >> 1; if(gg[mid] == sum) { if(pos == mid) return false; else return true; } if(gg[mid] > sum) l = mid + 1; if(gg[mid] < sum) r = mid - 1; } return false; } int main() { int t; scanf("%d" , &t); for(int i = 1 ; i <= t ; i++) { scanf("%lld" , &a[i]); } ll sum = 0; for(int i = 1 ; i <= t ; i++) { sum += a[i]; } if(sum % 2 != 0) { printf("NO "); } else { be[0] = 0; for(int i = 1 ; i <= t ; i++) { be[i] = be[i - 1] + a[i]; } af[t + 1] = 0; for(int i = t ; i >= 1 ; i--) { af[i] = af[i + 1] + a[i]; } ll aim = sum / 2; int flag = 0; for(int i = 1 ; i <= t ; i++) { if(be[i] == aim) {flag = 1; break;} } for(int i = 1 ; i <= t ; i++) { if(flag) break; bool temp = binsearch(0 , i , aim - a[i] , be , i); if(temp) {flag = 1; break;} temp = binsearch2(i , t + 1 , aim - a[i] , af , i); if(temp) {flag = 1; break;} } if(flag) printf("YES "); else printf("NO "); } return 0; }