题意:给定
n
个正整数,要求分成
dp[i]=max(dp[j])+1,(i−L<=j<i
&&
sum[j]⊗sum[i]<=X)
其中
sum[i]
记录前缀异或和
类似求解区间最大(小)异或连续子序列的方法,我们在字典树上依次插入前缀和。
对条件
i−L<=j<i
的维护,每次判断区间长度,多出就删除对应的前缀和。
对
sum[j]⊗sum[i]<=X)
的维护看上去很难,第一眼以为要在字典树上暴力DFS,其实不然。考虑第
i
个二进制位:
保证异或后值为
保证异或后值为
1
,继续走就好了(最多走完每个二进制位)。
其他一样的道理,也就是说没必要去跑DFS,只需扫一遍二进制位即可。
这里我们只需要维护一个
Max[u]
表示以
u
节点为
如果当前的
dp
值不存在,我直接插入的是
−1
比较无语的是:
10 5 5
1 1 1
结果应该是0,但是一直返回1。然后设个标记就神奇返回0,真心醉,估计哪里没写好。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <cstdlib>
#define ll o<<1
#define rr o<<1|1
#define CLR(a, b) memset(a, (b), sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<LL, LL> pii;
const int MAXN = 1e5 + 10;
const int INF = 1e7 + 10;
const int MOD = 1e9 + 7;
void add(LL &x, LL y) { x += y; x %= MOD; }
int f[31];
int X, l, A[MAXN], sum[MAXN], dp;
bool vis[MAXN];
int N;
int Next[MAXN * 30][2], root, L, word[MAXN * 30], Max[MAXN * 30], father[MAXN];
int newnode() {
Next[L][0] = Next[L][1] = -1;
father[L] = Max[L] = -1; word[L++] = 0;
return L - 1;
}
void init() { L = 0; root = newnode(); }
void PushUp(int u) {
while(u != root) {
u = father[u];
Max[u] = max(Max[Next[u][0]], Max[Next[u][1]]);
}
}
void Insert(int val, int ans) {
int u = root, v;
for(int i = 30; i >= 0; i--) {
v = val & f[i] ? 1 : 0;
if(Next[u][v] == -1) {
Next[u][v] = newnode();
}
father[Next[u][v]] = u;
u = Next[u][v]; word[u]++;
Max[u] = max(Max[u], ans);
}
PushUp(u);
}
void Delete(int val) {
int u = root, v;
for(int i = 30; i >= 0; i--) {
v = val & f[i] ? 1 : 0;
u = Next[u][v];
word[u]--;
if(word[u] == 0) {
Max[u] = -1;
}
}
PushUp(u);
}
int Query(int val) {
int u = root, v;
int ans = -1;
for(int i = 30; i >= 0; i--) {
v = val & f[i] ? 1 : 0;
// X
// 0 -> Next[u][v]:0
// 1 -> Next[u][v]:0, Next[u][v ^ 1]:1
if((X & f[i]) && Next[u][v] != -1) {
ans = max(ans, Max[Next[u][v]]);
}
if((X & f[i])) {
u = Next[u][v ^ 1];
}
else {
u = Next[u][v];
}
if(u == -1) {
break;
}
}
if(u != -1) ans = max(ans, Max[u]);
return ans;
}
int main()
{
f[0] = 1;
for(int i = 1; i <= 30; i++) {
f[i] = f[i - 1] * 2;
}
int t, kcase = 1; scanf("%d", &t);
while(t--) {
scanf("%d%d%d", &N, &X, &l);
int P, Q; scanf("%d%d%d", &A[1], &P, &Q);
sum[1] = A[1];
for(int i = 2; i <= N; i++) {
A[i] = (int)(1LL * A[i - 1] * P % 268435456 + Q) % 268435456;
sum[i] = sum[i - 1] ^ A[i];
}
sum[0] = 0; init(); CLR(vis, false);
Insert(sum[0], 0); int s = 0;
for(int i = 1; i <= N; i++) {
if(i - l > s) {
if(vis[s]) {
Delete(sum[s]);
}
s++;
}
dp = Query(sum[i]) + 1;
if(dp == 0) continue;
vis[i] = true; Insert(sum[i], dp);
}
printf("%d\n", dp);
}
return 0;
}