有关异或的一些习题整理
第一个:
给出一个序列
求子集的算术和的异或和
爆搜是不行的,但是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]); } }