标签:总数 define target 需要 scanf solution main 方案 mat
因为异或结果\(\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的教训)。
#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;
}
标签:总数 define target 需要 scanf solution main 方案 mat
原文地址:https://www.cnblogs.com/violetholmes/p/14257463.html