【CodeChef PREFIXOR】Prefix XOR

https://odzkskevi.qnssl.com/f0fbdb108ec813b1294f8f714805963b?v=1502083692

网上搜到的题解:

http://blog.csdn.net/zzkksunboy/article/details/76563303

xor的题,一般是考虑第一个不一样的位。

这个题当时考虑都是从字典树解决。这题可以对每个左边界找到最远的右边界,记作数组num[i]。

答案算两个部分,一个是num[i](l<=i<=r)小于等于r的,一个是num[i](l<=i<=r)大于r,第二部分答案要变成r。强制在线用主席树。

#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define dow(i,l,r) for(int i=r;i>=l;i--)
#define rep0(i,r) for(int i=0;i<r;i++)
#define repedge(i,x) for(int i=fi[x];i;i=e[i].next)
#define maxn 10001000
#define maxm 400400
#define LL long long
using namespace std;

int rson[maxn],lson[maxn],total=0,n,m,root[maxm],lst[40][2];
LL sz[maxn],sum[maxn];
int pre[maxm],num[maxm],a[maxm];

int getnew()
{
    ++total;
    sum[total]=sz[total]=lson[total]=rson[total]=0;
    return total;
}

void change(int &x,int old,int l,int r,LL y)
{
    //printf("%d %d %d %lld %lld %lld\n",x,l,r,sum[old],sz[old],y);
    x=getnew();
    sum[x]=sum[old]+y;
    sz[x]=sz[old]+1;
    lson[x]=lson[old];
    rson[x]=rson[old];
    if (l==r) return;
    int mid=(l+r)>>1;
    if (y<=mid) change(lson[x],lson[old],l,mid,y);
    else change(rson[x],rson[old],mid+1,r,y);
}

LL ask1(int x,int l,int r,int y)
{
    //printf("%d %d %d %lld %d %lld\n",x,l,r,sum[x],lson[x],sum[lson[x]]);
    if (!x) return 0;
    if (l==r) return sum[x];
    int mid=(l+r)>>1;
    if (y<=mid) return ask1(lson[x],l,mid,y);
    return sum[lson[x]]+ask1(rson[x],mid+1,r,y);
}

LL ask2(int x,int l,int r,int y)
{
    if (!x) return 0;
    if (l==r) return sz[x];
    int mid=(l+r)>>1;
    if (y<=mid) return sz[rson[x]]+ask2(lson[x],l,mid,y);
    return ask2(rson[x],mid+1,r,y);
}

void pput(int x,int l,int r)
{
    printf("%d %d %d %lld %lld\n",x,l,r,sum[x],sz[x]);
    if (l==r) return;
    int mid=(l+r)>>1;
    pput(lson[x],l,mid);
    pput(rson[x],mid+1,r);
}

int main()
{
  //  freopen("1.in","r",stdin);
    scanf("%d",&n);
    sum[0]=sz[0]=lson[0]=rson[0]=0;
    pre[0]=0;
    rep(i,1,n) {
        scanf("%d",&a[i]);
        pre[i]=pre[i-1]^a[i];
    }
    rep0(i,31) lst[i][0]=lst[i][1]=n;
    dow(i,1,n) {
      //  printf("%d:\n",i);
        int ch1,ch2;
        if (a[i+1]) {
            dow(j,0,30) {
                ch1=(pre[i]>>j)&1;
                ch2=(pre[i+1]>>j)&1;
                if (ch1!=ch2) {
                    lst[j][ch2]=i;
                    break;
                }
            }
        }
        num[i]=n;
        dow(j,0,30) {
            ch1=(pre[i-1]>>j)&1;
            num[i]=min(num[i],lst[j][ch1]);
        }
      //  rep(j,0,4) printf("%d %d %d\n",j,lst[j][0],lst[j][1]);
      //  printf("\n");
    }
   // rep(i,1,n) printf("%d %d\n",i,num[i]);
   // printf("\n");
    root[0]=0;
    rep(i,1,n) {
        change(root[i],root[i-1],1,n,(LL)num[i]);
        //printf("%lld %lld\n",sum[root[i]],sz[root[i]]);
    }
   // rep(i,1,n) {
   //     printf("%d:\n",i);
   //     pput(root[i],1,n);
   // }
    LL last=0,ans=0;
    scanf("%d",&m);
    while (m--) {
        LL l,r;
        scanf("%lld %lld",&l,&r);
        l=(l+last)%n+1;
        r=(r+last)%n+1;
        if (l>r) swap(l,r);
        //printf("%lld %lld\n",l,r);
        LL ans=-(r+l-2)*(r-l+1)/2;
        l--;
        //printf("%lld\n",ans);
        //printf("%lld\n",ask1(root[r],1,n,r));
        ans+=ask1(root[r],1,n,r);
        //printf("%lld\n",ans);
        if (r<n) ans+=ask2(root[r],1,n,r+1)*r;
        //printf("\t%lld\n",ans);
        if (l>0) ans-=ask1(root[l],1,n,r);
        //printf("%lld\n",ans);
        if (r<n && l>0) ans-=ask2(root[l],1,n,r+1)*r;
        printf("%lld\n",last=ans);
        //printf("/----------------------/\n");
    }
    return 0;
}

时间: 2024-12-20 16:31:19

【CodeChef PREFIXOR】Prefix XOR的相关文章

【BZOJ 2115】 [Wc2011] Xor

2115: [Wc2011] Xor Time Limit: 10 Sec  Memory Limit: 259 MB Submit: 962  Solved: 441 [Submit][Status] Description Input 第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目. 接下来M 行描述 M 条边,每行三个整数Si,Ti ,Di,表示 Si 与Ti之间存在 一条权值为 Di的无向边. 图中可能有重边或自环. Output 仅包含一个整数,表示最大的XOR和(十进

【线性基】hdu3949 XOR

给你n个数,问你将它们取任意多个异或起来以后,所能得到的第K小值? 求出线性基来以后,化成简化线性基,然后把K二进制拆分,第i位是1就取上第i小的简化线性基即可.注意:倘若原本的n个数两两线性无关,也即线性基的大小恰好为n时,异或不出零,否则能异或出零,要让K减去1. 这也是线性基的模板. #include<cstdio> #include<cstring> using namespace std; typedef long long ll; ll d[64],p[64]; int

【BZOJ 4269】再见Xor

zky学长提供的线性基求法: for(int i=1;i<=n;i++) for(int j=64;j>=1;j--) { if(a[i]>>(j-1)&1) { if(!lb[j]){lb[j]=a[i];break;} else a[i]^=lb[j]; } } Gauss消元求线性基的方法: #include<cstdio> #include<cstring> #include<algorithm> #define read(x)

【CodeChef】Small factorials(BigInteger笔记)

You are asked to calculate factorials of some small positive integers. Input An integer t, 1<=t<=100, denoting the number of testcases, followed by t lines, each containing a single integer n, 1<=n<=100. Output For each integer n given at inpu

【Math】GCD XOR 证明

题目:Given an integer N, and how many pairs (A;B) are there such that: gcd(A;B) = A xor B where 1<=B<=A<=N. 首先先爆一发,妥妥超时.其实真相是我想打表找规律.结果没什么规律可循. 后来分析:要想让GCD(A,B)==(A^B),A和B一定是同样的位数(二进制).因此打表方法可变为:(亦超时) void init() { int K=0; int last=0; for(int i=1;

【高斯消元解XOR方程】POJ1222-EXTENDED

[题目大意] 有5*6盏灯,每次开/关一个灯,上下左右的灯状态也会反转.问怎么使状态统一? [思路] 典型高斯消元解XOR方程,注意每盏灯要么0次要么1次. 1 #include <iostream> 2 #include <stdio.h> 3 #include <algorithm> 4 #include <set> 5 using namespace std; 6 int a[40][40]; 7 void gauss() 8 { 9 int i,j,

【CodeChef】Turbo Sort

题目链接:Turbo Sort 用java自带O(NlogN)的排序就可以,java要特别注意输入输出.输入用BufferedReader,输出用printWriter.printWriter的速度比System.out快很多,参考StackOverflow. 代码: 1 import java.io.BufferedOutputStream; 2 import java.io.BufferedReader; 3 import java.io.InputStreamReader; 4 impor

【CodeChef】Factorial(n!末尾0的个数)

The most important part of a GSM network is so called Base Transceiver Station (BTS). These transceivers form the areas called cells (this term gave the name to the cellular phone) and every phone connects to the BTS with the strongest signal (in a l

【BZOJ2337】[HNOI2011]XOR和路径 期望DP+高斯消元

[BZOJ2337][HNOI2011]XOR和路径 Description 题解:异或的期望不好搞?我们考虑按位拆分一下. 我们设f[i]表示到达i后,还要走过的路径在当前位上的异或值得期望是多少(妈呀好啰嗦),设d[i]表示i的度数.然后对于某条边(a,b),如果它的权值是1,那么f[b]+=(1-f[a])/d[a]:如果它的权值是0,那么f[b]+=f[a]/d[a],然后我们移个项,就变成了一堆方程组求解,直接高斯消元. 别忘了f[n]=0! #include <cstdio> #i