zoukankan      html  css  js  c++  java
  • codeforces|CF1054D Changing Array

    因为数据范围是2e5级别的,所以我们考虑用异或前缀和来处理区间的异或情况。(比如说a包括b,那么我们通过异或可以知道b对于a的补区间的信息)

    之后因为对任意(a_i)进行取反操作,会改变它和它之后的区间值(原来相等的都不相等了,原来不相等的都相等了),所以结果是我们对原先的前缀和直接取反,就可以表示对它进行取反操作之后的前缀和了。

    因为不管怎么取反操作,一个位置的前缀和只有两种,那么我们显然就可以预处理出所有的值了。

    然后我们可以把相同类别的放在一个map里面。(注意要避免重复,比如说010和101是一类)

    之后把ans值((==n*(n+1)/2))减去重复的就可以了。

    因为是要求区间异或和不为0,那么转化下来的条件就是前缀和选取的两个不相等即可。

    我们要求最大的个数,那么就是同一类的最好均分,用组合数算就行了。(比如说有5个010的话,分成2个010和3个101就行了)

    最后注意一下要先给0类加一。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<map>
    #define MAXN 200010
    using namespace std;
    long long ans;
    int pre[MAXN];
    map<int,int>m;
    int n,k,x;
    int main() {
    	scanf("%d%d",&n,&k);
    	m[0]++;
    	for(int i=1;i<=n;i++) 
    	{
    		scanf("%d",&x);
    		pre[i]=pre[i-1]^x;
    		pre[i]=min(pre[i],pre[i]^((1<<k)-1));
    		m[pre[i]]++;
    	}
    	ans=(long long)(n+1)*n/2;
    	for (map<int,int>::iterator it=m.begin();it!=m.end();it++) 
    	{
    		long long x=it->second;
    		ans-=(long long)((x/2)-1)*(x/2)/2;
    		ans-=(long long)((x-x/2)-1)*(x-x/2)/2;
    	}
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    [转]Linux(Ubuntu)下如何安装JDK
    第一个MICO CORBA demo实录
    解决/usr/bin/ld: cannot find -lssl
    使用adb shell 进入手机修改文件的权限
    解决某些Android Permission denied
    Java 8新特性终极指南
    Win10系统出问题?简单一招即可修复win10!
    运行时数据区
    linux下vi命令大全
    关于java中final关键字与线程安全性
  • 原文地址:https://www.cnblogs.com/fengxunling/p/9816452.html
Copyright © 2011-2022 走看看