2017.10.12 小Q的无敌异或 失败总结

第一问是可以O(n)的

二进制位是独立的,所以直接分开算即可。。

记一个前缀和,开桶装0、1的个数     然后每次新加入一个点就直接更新就可以了


第二问就比较难了,,手玩只能发现最低位可以这么搞,对于高位还要考虑借位情况,借位情况有0有1,就不好离散

但是这么做是可以做出来的。。只是要在模意义下进行,,再考虑每次-的过程,都是一个前缀和-比他靠前的前缀和,

当差值>枚举次数时,显然影响是1  

差值要考虑进位的情况,,这样似乎就形成了一个偏序关系,,就可以用树状数组了。。


码(借鉴):

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define P 998244353
ll ans,n,j,i,k,lin,er[50],he[50][100005],lie[100005],dui[100005],v[100005],a[100005],tong[100006],p[100005];
 
int lowbit(int a)
{
    return a&(-a);
}
 
void jia(int o,int z)
{
    for(;o<=dui[0];o+=lowbit(o))
    {
        v[o]^=z;
    }   
}
int cha(int o)
{
    int ans=0;
    for(;o;o-=lowbit(o))
    {
        ans^=v[o];
    }return ans;
}
int find(ll o)
{
    if(o<0)return 0;
    int l=1,r=dui[0]+1;
    while(l+1<r)
    {
    int mid=(l+r)>>1;
    if(dui[mid]<=o)l=mid;
    else r=mid; 
    }   
    return l;
}
 
 
 
int main()
{   
    er[0]=1;
    for(i=1;i<=40;i++)
    er[i]=er[i-1]*2;
    scanf("%lld",&n);
    for(i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);        
    }
    for(i=0;i<=20;i++)
    for(j=1;j<=n;j++)
    {
    he[i][j]=he[i][j-1]^(a[j]&er[i]);
    if(he[i][j]&er[i])tong[i]++;
    }
    for(i=0;i<=20;i++)
    {
        for(j=1;j<=n;j++)
        {
    ans=1ll*(ans+1ll*tong[i]*er[i])%P;
    if(a[j]&er[i])
    {
        tong[i]=(n-j)-(tong[i]-1);
    }       
        }       
    }
    printf("%lld ",ans);
    ans=0;
      for(i=1;i<=n;i++)he[0][i]=he[0][i-1]+a[i];  
    for(k=0;k<=37;k++){  
        for (i=0; i<=n; i++) tong[i]=p[i]=he[0][i]&(er[k+1]-1);  
        dui[0]=0;
        sort(tong,tong+n+1); dui[++dui[0]]=tong[0];  
        memset(v,0,sizeof(v));  
        for (i=1; i<=n; i++)  
            if (tong[i]!=tong[i-1]) dui[++dui[0]]=tong[i];  
        int lin=0;  
        for (i=0; i<=n; i++){  
            lin^=cha(find(p[i]-er[k]))^cha(find(p[i]))^cha(find(p[i]+er[k]));  
            //cout<<er[k]<<" "<<lin<<" ";
            jia(find(p[i]),1);    
        } //cout<<lin<<endl; 
        if (lin) ans|=er[k];  
         
    }  
    printf("%lld",ans);
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值