Codeforces Round #512 Div. 1 B. Vasya and Good Sequences 分治
阿新 • • 發佈:2018-12-11
Description 給你一個序列,問有多少個區間[l,r]滿足l~r的每一個數01隨意排列異或和為0。
Sample Input 3 6 7 14
Sample Output 2
你可以發現一個性質: 一個區間內的數總和為偶數,且總和大於最大的數乘二就肯定滿足條件,根據這個進行分治即可。 好像還是可以直接DP的,設f[i][j]為列舉到第i個數有j個1未配對的情況,轉移即可。 我寫的是分治,因為我想出了性質。。。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; int _min(int x, int y) {return x < y ? x : y;} int _max(int x, int y) {return x > y ? x : y;} LL read() { LL s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar(); return s * f; } int S[2][2][200]; LL ans, a[310000]; LL n, bin[61]; int lowbit(int x) {return x & -x;} void change(int x, int c, int opt, int hh) {for(int i = x; i <= 130; i += lowbit(i)) S[hh][opt][i] += c;} int getsum(int x, int opt, int hh) {int sum = 0; for(int i = x; i; i -= lowbit(i)) sum += S[hh][opt][i]; return sum;} void clear(int x, int opt, int hh) {for(int i = x; i <= 130; i += lowbit(i)) S[hh][opt][i] = 0;} void solve(int l, int r) { if(l == r) return ; int mid = (l + r) / 2; solve(l, mid), solve(mid + 1, r); int sum = 0, maxx = 0; for(int i = mid; i >= l; i--) { sum += a[i], maxx = _max(maxx, a[i]); int o = _max(0, maxx * 2 - sum) + 1; change(o, 1, sum % 2, 0); } int maxx1 = 0, sum1 = 0, sum2 = 0, maxx2 = 0; int tp = mid + 1; for(int i = mid + 1; i <= r; i++) { maxx1 = _max(maxx1, a[i]), sum1 += a[i]; while(tp > l && maxx1 > a[tp - 1]) { sum2 += a[--tp]; maxx2 = _max(maxx2, a[tp]); int o = _max(0, maxx2 * 2 - sum2) + 1; change(130 - _min(sum2, 129), 1, sum2 % 2, 1); change(o, -1, sum2 % 2, 0); } ans += getsum(130 - _max(0, maxx1 * 2 - sum1), sum1 % 2, 1); ans += getsum(_min(sum1, 129) + 1, sum1 % 2, 0); } sum = maxx = 0; for(int i = mid; i >= l; i--) { sum += a[i], maxx = _max(maxx, a[i]); int o = _max(0, maxx * 2 - sum) + 1; clear(o, sum % 2, 0), clear(130 - _min(sum, 129), sum % 2, 1); } } int main() { n = read(); bin[0] = 1LL; for(int i = 1; i <= 60; i++) bin[i] = bin[i - 1] * 2LL; for(int i = 1; i <= n; i++) { LL x = read(); for(int j = 60; j >= 0; j--) if(x >= bin[j]){ a[i]++, x -= bin[j]; } } ans = 0; solve(1, n); printf("%lld\n", ans); return 0; }