题意
在线求a[l,r]间最大连续子串xor和。
题解
我的程序竟然排Rank 4,不科学。。。
a[l,r]
的xor和转化为
b[l−1]
xor
b[r]
那么问题转化为求
b[l−1,r]
的任意2个数的xor和的最大值。
如果一个数固定,那么就可以把问题转化为BZOJ 3261。
所以我们每
n−−√
取一个数,预处理出它到后面每个数的xor的最大值,比如对于
a[n−−√]
到
a[j]
,我们先假定
a[j]
前的范围的最大xor值已求得,那么我们固定
a[j]
,那么这段数中找与a[j]的xor和的最大值为
O(logm)
。而对于
a[j]
之前的数,我们之前已经先求得了,递推一下就好了。似乎是个dp?
预处理的复杂度为
O(nn−−√logm)
,每
n−−√
取一次数,枚举该数后面的数,查询Trie。
那么对于每个询问就好办了。
假如我们查询
[l,r]
,那么先判定区间内有无之前每
n−−√
取的数,那么该数到r这段区间的最大xor值已经预处理出来了。对于l到该数间的数我们暴力查询Trie就可以了,因为数目不会超过
O(n−−√)
。
每个询问的复杂度为
O(n−−√logm)
可以尝试把块的大小改一下,测试发现分块开109比110要快一些。。
代码
#include <cstdio>
#include <algorithm>
#define FOR(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int N = 12002;
struct Trie {
Trie* c[2]; int size;
Trie() { c[0] = c[1] = this; size = 0; }
Trie(Trie *l, Trie *r, int sz) { c[0] = l, c[1] = r, size = sz; }
void* operator new(size_t) {
static Trie pool[N * 35], *pointer = pool;
return pointer++;
}
static Trie* put(Trie *p, int x, int digit) {
if (!digit)
return new Trie(p->c[0], p->c[1], p->size + 1);
if (x & digit)
return new Trie(p->c[0], put(p->c[1], x, digit >> 1), p->size + 1);
else
return new Trie(put(p->c[0], x, digit >> 1), p->c[1], p->size + 1);
}
static int get(Trie *p1, Trie *p2, int x, int digit) {
if (!digit)
return 0;
int t = bool(~x & digit);
if (p1->c[t]->size - p2->c[t]->size)
return digit | get(p1->c[t], p2->c[t], x, digit >> 1);
else
return get(p1->c[t ^ 1], p2->c[t ^ 1], x, digit >> 1);
}
} *trie_impl[N], **trie = trie_impl + 1;
const int block = 109;
const int dep = 1 << 30;
int w[115][N];
int b[N], n, m;
int main() {
int lastans = 0, l, r, x, y, i, j;
scanf("%d%d", &n, &m);
FOR(i,1,n) scanf("%d", &b[i]), b[i] ^= b[i - 1];
trie[-1] = new Trie();
FOR(i,0,n) trie[i] = Trie::put(trie[i - 1], b[i], dep);
FOR(i,1,n) FOR(j, 0, i / block)
w[j][i] = max(w[j][i - 1], Trie::get(trie[j * block - 1], trie[i], b[i], dep));
FOR(i,1,m) {
scanf("%d%d", &x, &y);
l = min(((x + lastans) % n) + 1, ((y + lastans) % n) + 1) - 1;
r = max(((x + lastans) % n) + 1, ((y + lastans) % n) + 1);
int ans = 0, l_id = l / block, r_id = r / block, j;
ans = w[l_id + 1][r];
FOR(j, l, min(r, (l_id + 1) * block))
ans = max(ans, Trie::get(trie[l - 1], trie[r], b[j], dep));
printf("%d\n", ans);
lastans = ans % n;
}
return 0;
}
Markdown的编辑器似乎并没有办法把网页格式保留下来?
原题
2741: 【FOTILE模拟赛】L
Time Limit: 15 Sec Memory Limit: 162 MB
Submit: 1817 Solved: 493
Description
FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和。
即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 … xor Aj),其中l<=i<=j<=r。
为了体现在线操作,对于一个询问(x,y):
l = min ( ((x+lastans) mod N)+1 , ((y+lastans) mod N)+1 ).
r = max ( ((x+lastans) mod N)+1 , ((y+lastans) mod N)+1 ).
其中lastans是上次询问的答案,一开始为0。
Input
第一行两个整数N和M。
第二行有N个正整数,其中第i个数为Ai,有多余空格。
后M行每行两个数x,y表示一对询问。
Output
共M行,第i行一个正整数表示第i个询问的结果。
Sample Input
3 3
1 4 3
0 1
0 1
4 3
Sample Output
5
7
7
HINT
N=12000,M=6000,x,y,Ai在signed longint范围内。