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

版权声明:xgc原创文章,未经允许不得转载。 https://blog.csdn.net/xgc_woker/article/details/82830755

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

猜你喜欢

转载自blog.csdn.net/xgc_woker/article/details/82830755