CF1054D Solution

题目链接

题解

因为异或结果\(\not=0\)的情况过多,我们可以转为考虑结果\(=0\)的情况,用总数减去这些区间即可。每一个数都可以和包括自己的\(n\)个数组为区间,因此总数\(=\frac{n(n+1)}{2}\)

至于如何求结果\(=0\)的方案数,可以想到前缀和,但枚举左右端点需要\(O(n^2)\)的时间。进一步思考,我们只需要区间数量而不需要求出具体的区间。因为异或的逆运算是其本身,所以当\(sum_{r}\oplus sum_{l-1}=0\)时区间\([l,r]\)和为\(0\),因此对于每一个\(r\)\(sum_{l-1}=sum_r\)\(l\)的个数即为右端点为\(r\)且区间异或和为\(0\)的区间个数,具体实现用\(map[i]\)记录\(sum=i\)的元素个数即可。

此外还有变换操作,易得该操作的实质是\(a_i\oplus 2^k-1\)。对于\(a_i\),在变换与不变换中取最小值即可。

又及:当前缀和\(0\)的时候是不可以取\([1,r]\)区间的,因此\(map[0]=1\)(WA的教训)。

AC代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;
int a[N];
map<int,int> mp;
signed main()
{
	int n,k,lst=0,ans=0;
	scanf("%lld%lld",&n,&k);
	int mov=(1<<k)-1; mp[0]=1;
	for(int i=1;i<=n;i++) 
	{
		scanf("%lld",&a[i]);
		int qwq=lst^a[i]; int qaq=qwq^mov;//qwq:不变换,qaq:变换
		if(mp[qwq]<mp[qaq]) {ans+=(mp[qwq]++); lst=qwq;}//不变换更优
		else {ans+=(mp[qaq]++); lst=qaq;}//变换更优
	}
	printf("%lld",n*(n+1)/2-ans);
	return 0;
}
posted @ 2021-01-10 10:10  violet_holmes  阅读(40)  评论(0编辑  收藏  举报