关于xor

有关异或的一些习题整理


 

第一个:

给出一个序列

求子集的算术和的异或和

爆搜是不行的,但是STL库很好

bitset

#include <cstdio>
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
using namespace std;

#define MAXN 2000001
bitset <MAXN> a;
int n,x,h,ans;
int main() {
    cin>>n;
    a[0]=1;
    for (int i=1;i<=n;i++) {
        cin>>x;
        a^=(a<<x);
        h+=x;
    }
    for (int i=h;i;i--) {
        if (a[i]) {
            ans^=i;
        }
    }
    cout<<ans<<endl;
    return 0;
}

然后呢?


 

下面一个:

奶牛异或:

在一个序列中,找一段连续子序列异或和最大:

#include <cstdio>
#include <iostream>
#include <string>
#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef unsigned long long ull;

const int MAXN = 50005;
const int maxnode = MAXN * 33;
const int sigma_size = 2;
const int INF = (1LL << 31) - 1;

struct Trie {
    int ch[maxnode][sigma_size];
    int val[maxnode];
    int sz;
    void clear() {
        sz = 1;
        memset(ch[0], 0, sizeof(ch[0]));
    }
    Trie() {
        clear();
    }

    int idx(char c) {
        return c - '0';
    }
    void insert(char *s, int v) {
        int u = 0, n = strlen(s);
        for(int i = 0; i < n; i++) {
            int c = idx(s[i]);
            if(!ch[u][c]) {
                memset(ch[sz], 0, sizeof(ch[sz]));
                val[u] = 0;
                ch[u][c] = sz++;
            }
            u = ch[u][c];
        }
        val[u] = v;
    }

    //^0 equal
    //^1 opposite
    int find(char *s, int value, int dir) {
        int u = 0, n = strlen(s);
        for(int i = 0; i < n; i++) {
            int c = idx(s[i]);
            int v = c ^ dir;
            if(!ch[u][v])
                v ^= 1;
            u = ch[u][v];
        }
        return val[u] ^ value;
    }

} trie;

int n, sum[MAXN], A[MAXN];
char bit[33];

void trans(char *s, int v) {
    for(int i = 31; i >= 0; i--)
        s[i] = ((v >> i) & 1) + '0';
    s[32] = '\0';
    reverse(s, s+32);
}

int f[101][101];

int main() {
    scanf("%d", &n);
    sum[0] = 0;
    for(int i = 1; i <= n; i++) {
        scanf("%d", &A[i]);
        sum[i] = sum[i-1] ^ A[i];
    }
    trans(bit, 0);
    trie.insert(bit, 0);
    int maxv = -INF, minv = INF;
    int mx, mi;
    for(int i = 1; i <= n; i++) {
        trans(bit, sum[i]);
        mi = trie.find(bit, sum[i], 0);
        mx = trie.find(bit, sum[i], 1);
        minv = min(mi, minv);
        maxv = max(mx, maxv);
        trie.insert(bit, sum[i]);
    }

    //printf("%d %d\n", maxv, minv);
    cout<<maxv<<" ";
    for (int i=1;i<=n;i++) {
        f[i][i]=A[i];
    }
    for (int l=2;l<=n;l++) {
        for (int i=1;i+l-1<=n;i++) {
            int j=i+l-1;
            f[i][j]=f[i][j-1]^A[j];
        }
    }
    for (int i=1;i<=n;i++) {
        for (int j=i+1;j<=n;j++) {
            if (f[i][j]==maxv) {
                cout<<i<<" "<<j<<endl;
                return 0;
            }
        }
    }
    return 0;
}

然后呢?


 

下面一个:

求一个序列所有连续和的异或值

#include <cstdio>
#include <iostream>
#include <string>
#include <bits/stdc++.h>

using namespace std;
#define MAXN 1000001
int c[MAXN][2];
int s[MAXN],a[MAXN],ans;
int pw[21],n;

void add(int x,int y) {
    while (x<=1000000) {
        c[x][y]++;
        x+=(x&(-x));
    }
}
int query(int x,int y) {
    int sum=0;
    while (x) {
        sum+=c[x][y];
        x-=(x&(-x));
    }
    return sum;
}
int main() {
    int flag,cnt;
    cin>>n;
    for (int i=1; i<=n; i++) {
        scanf("%d",&s[i]);
        s[i]+=s[i-1];
    }
    pw[0]=1;
    for (int i=1; i<=20; i++)
        pw[i]=pw[i-1]*2;
    for (int i=0; i<=20; i++) {
        if (pw[i]<=s[n]) {
            memset(c,0,sizeof(c));
            flag=0;
            add(1,0);
            for (int j=1; j<=n; j++) {
                int tmp=s[j]&pw[i];
                if (tmp) {
                    cnt=query(a[j]+1,0)+query(1000001,1)-query(a[j]+1,1);
                } 
                else  {
                    cnt=query(a[j]+1,1)+query(1000001,0)-query(a[j]+1,0);
                }
                if (cnt%2==1) flag^=1;
                add(a[j]+1,(bool)tmp);
                if (tmp)  {
                    a[j]|=pw[i];
                }
            }
            if (flag) {
                ans|=(pw[i]);
            } 
        }
    }
    cout<<ans;
    return 0;
}

下面呢?


 

再来一个:

 给定序列
多次输入起点终点
求起点连续异或到终点的值

#include <cstdio>
#include <iostream>
#include <string>
#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef unsigned long long ull;

/*
给定序列
多次输入起点终点
求起点连续异或到终点的值 
*/

void init()
{
    int n=0,sum=0;
    for(int i=1; i<=100; i++)
    {
        printf("%d %d\n",n,sum);
        n^=i;
        sum^=n;
    }
}
long long xo(int x)///A0xorA1...xorAx
{
    long long n=0,sum=0;
    if(x<=7)
        for(int i=1; i<=x; i++)
            {
                n^=i;
                sum^=n;
            }
    else
    {
        int m=x;
        m-=7;
        int pos=m%8;
        if(x<4)
            for(int i=1; i<=x; i++)
                n^=i;
        m-=3;
        int pos1=n%4;
        for(int i=x-pos1+1; i<=x; i++)
                n^=i;
        for(int i=x-pos+1; i<=x; i++)
            {
                n^=i;
                sum^=n;
            }
    }
    return sum;
}
int main()
{
    int T,l,r;
    //init();
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d",&l,&r);
        printf("%lld\n",xo(r)^xo(l-1));
    }
    return 0;
}

接下来 还有:


 

下一个:

给定序列
求连续子区间异或值的和:

#include <cstdio>
#include <iostream>
#include <string>
#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef unsigned long long ull;

/*
给定序列
求连续子区间异或值的和
*/

const int maxn = 2e5+7;
int sum[maxn],a[maxn],c[maxn];
int main() {
    int n;
    scanf("%d",&n);
    sum[0] = 0;
    for(int i=1; i<=n; i++) {
        scanf("%d",&a[i]);
        sum[i] = sum[i]^a[i];
    }
    int ans = 0;
    for(int k=0; k<=29; k++) {
        c[0] =1 ,c[1] =0;
        for(int i=1; i<=n; i++) {
            int v = (sum[i]&(1<<k))?1:0;
            ans+=((1<<(k))*c[v^1])%mod;
            c[v]++;
        }
    }
    cout<<ans<<endl;
    return 0;
}

下面还有:


 

然后呢?

给定序列
给出l,r
求l,r之间多少个子区间异或值为k:

传说中的莫队算法:

#include <cstdio>
#include <iostream>
#include <string>
#include <bits/stdc++.h>

/*
给定序列
给出l,r
求l,r之间多少个子区间异或值为k 
*/

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll maxn = 1e5 + 6;
ll a[maxn];
ll ans[maxn];
ll sum[maxn];
ll c[maxn];
ll n, m, k;
ll unit;
ll tmp;
 
struct node {
    ll l, r, id;
}t[maxn];
 
ll cmp(node a, node b) {
    if (a.l / unit != b.l / unit)return a.l / unit < b.l / unit;
    return a.r < b.r;
}
 
void add(ll id) {
    tmp += c[a[id] ^ k];
    c[a[id]]++;
}
 
void dele(ll id) {
    c[a[id]]--;
    tmp -= c[a[id] ^ k];
}
 
void work() {
    c[0] = 1;
    ll L = 1;
    ll R = 0;
    tmp = 0;
    for (ll i = 1; i <= m; i++) {
        while (L > t[i].l) { L--; add(L - 1); }
        while (L < t[i].l) { dele(L - 1); L++; }
        while (R > t[i].r) { dele(R); R--; }
        while (R < t[i].r) { R++; add(R); }
        ans[t[i].id] = tmp;
    }
}
 
int main() {
    scanf("%lld%lld%lld", &n, &m, &k);
    for (ll i = 1; i <= n; i++)scanf("%lld", &a[i]),a[i]^=a[i-1];
    for (ll i = 1; i <= m; i++) {
        scanf("%lld%lld", &t[i].l, &t[i].r);
        t[i].id = i;
    }
    unit = (ll)sqrt(n);
    sort(t + 1, t + 1 + m, cmp);
    work();
    for (ll i = 1; i <= m; i++) {
        printf("%lld\n", ans[i]);
    }
}

 

posted @ 2018-10-29 20:20  codemaker_li  阅读(203)  评论(0编辑  收藏  举报