1. 程式人生 > >Codeforces Round #512 Div. 1 B. Vasya and Good Sequences 分治

Codeforces Round #512 Div. 1 B. Vasya and Good Sequences 分治

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;
}