首页 > 代码库 > uva live 7639 Extreme XOR Sum (暴力+二项式)
uva live 7639 Extreme XOR Sum (暴力+二项式)
题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=5661
题意:
给你一个长度为n的整数序列,询问任意区间的极端异或和。
定义极端异或和:
当长度n > 1 的时候,将数组长度缩小到n-1。
[a1, a2, a3 ···, an] -> [a1⊕a2, a2⊕a3, a3⊕a4, ···, an-1⊕an]。
一直缩小,直到长度减为1, 就是极端异或和。
题解:
[a1, a2, a3, a4, a5] 操作时
第一次:[a1⊕a2, a2⊕a3, a3⊕a4, a4⊕a5]
第二次:[a1⊕a2⊕a2⊕a3 , a2⊕a3⊕a3⊕a4, a3⊕a4⊕a4⊕a5]
以此类推到最后我们发现 a1用了1次, a2用了4次, a3用了6次, a4用了4次, a5用了1次。
1 4 6 4 1。这个正好是C(0,4) C(1,4) C(2,4) C(3,4) C(4,4)。
满足二项式的系数。
所以对于长度为n的时候,我们需要C(n-1)的系数。
我们就可以预处理C数组。
1 memset(C, 0); 2 for(int i = 0;i<=n;i++){ 3 C[i][0] = 1; 4 for(int j = 1;j<=i;j++) C[i][j] = C[i-1][j-1] + C[i-1][j]; 5 }
因为只需要考虑奇偶性,就可以 C[i][j] = (C[i-1][j-1] + C[i-1][j])%2
在第i个位置判断为奇数的时候就异或一下就可以得到ans了。
但是一次询问O(n) 的复杂度,会导致TLE。就需要优化一下。
我们可以发现 %2 的操作其实就 xor的操作。
1 int C[maxn]; 2 vector <int> pos[maxn]; 3 void init() 4 { 5 ms(C, 0); 6 for(int i = 1;i<maxn;i++) 7 { 8 C[0] = C[i-1] = 1; 9 for(int j = i-2;j>=1;j--) C[j] = C[j-1]^C[j]; 10 for(int j = 0;j<i;j++) 11 if(C[j]) 12 pos[i].pb(j); 13 } 14 }
这里减少了一维的空间(可以参考01背包那里),因为都是滚动数组。
将第j个位置是奇数,记录起来。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 #include <algorithm> 6 #include <cmath> 7 #include <vector> 8 #include <queue> 9 #include <map> 10 #include <stack> 11 #include <set> 12 using namespace std; 13 typedef long long LL; 14 typedef unsigned long long uLL; 15 #define ms(a, b) memset(a, b, sizeof(a)) 16 #define pb push_back 17 #define mp make_pair 18 #define eps 0.0000000001 19 #define IOS ios::sync_with_stdio(0);cin.tie(0); 20 const LL INF = 0x3f3f3f3f3f3f3f3f; 21 const int inf = 0x3f3f3f3f; 22 const int mod = 1e9+7; 23 const int maxn = 10000+10; 24 int a[maxn]; 25 int C[maxn]; 26 vector <int> pos[maxn]; 27 void init() 28 { 29 ms(C, 0); 30 for(int i = 1;i<maxn;i++) 31 { 32 C[0] = C[i-1] = 1; 33 for(int j = i-2;j>=1;j--) C[j] = C[j-1]^C[j]; 34 for(int j = 0;j<i;j++) 35 if(C[j]) 36 pos[i].pb(j); 37 } 38 } 39 void solve() 40 { 41 int n;scanf("%d", &n); 42 for(int i = 0;i<n;i++) scanf("%d", &a[i]); 43 int q;scanf("%d", &q); 44 while(q--){ 45 int l, r;scanf("%d%d", &l, &r); 46 int len = r-l+1; 47 int ans = 0; 48 int sz = pos[len].size(); 49 for(int k = 0;k<sz;k++){ 50 ans ^= a[pos[len][k]+l]; 51 } 52 printf("%d\n", ans); 53 } 54 } 55 int main() { 56 #ifdef LOCAL 57 freopen("input.txt", "r", stdin); 58 // freopen("output.txt", "w", stdout); 59 #endif 60 // IOS 61 init(); 62 int t;scanf("%d", &t); 63 int cnt = 1; 64 while(t--){ 65 printf("Case %d:\n", cnt++); 66 solve(); 67 } 68 return 0; 69 }
还有一个用Sierpinski sieve优化的,附上链接:http://morris821028.github.io/categories/%E8%A7%A3%E9%A1%8C%E5%8D%80/%E8%A7%A3%E9%A1%8C%E5%8D%80-UVa/
uva live 7639 Extreme XOR Sum (暴力+二项式)