给定5个参数,分别为 N,A,B,P,M 其中我们可以生成字符串 c 中的第 i 位 ci=[(A∗i+B)modN≥B] ,下标为 0 ~ N−1 ,并且这个字符串是循环的。现在给你另一个 M 为的字符串 S ,现在有 Q 组操作,有两种:每种都给定一个 p 。
1. 询问 c 的第 p 位开始往取 M 位得到的字符串与 S 有多少位不同。
2. 将 S 的第 p 为取反。
N≤109
1≤A,B,P,M≤N
1≤N,Q≤105
如果我们直接拿生成的字符串去做,那么这个是很难维护了,那么我们考虑把 (A∗i+B)modN 相同的分成一类。我们考虑 c 中的哪些字符串的第 i 位于 Si 不相等。根据上面那条式子,移一下项。如果我们把按 (A∗i+B)modN 为下标的话,那么对应的位置肯定是连续一段的,那么我们就可以用线段树来维护一段区间覆盖的点。最后的答案就是 (A∗cp+B)modN 被覆盖了多少次。
//YxuanwKeith
#include
#include
#include
using namespace std;
const int MAXN = 1e5 + 5;
struct Node {
int l, r, Num;
} Tr[MAXN * 50];
int tot, Q, N, A, B, P, M, Root;
char S[MAXN], C[10];
int Calc(int i) {
return (1ll * i * A + B) % N;
}
int Query(int Now, int l, int r, int Side) {
if (!Now) return 0;
if (l == r) return Tr[Now].Num;
int Mid = (l + r) >> 1;
if (Side <= Mid) return Tr[Now].Num + Query(Tr[Now].l, l, Mid, Side); else
return Tr[Now].Num + Query(Tr[Now].r, Mid + 1, r, Side);
}
void Modify(int &Now, int l, int r, int lx, int rx, int val) {
if (rx < l || lx > r) return;
if (!Now) Now = ++ tot;
if (l >= lx && r <= rx) {
Tr[Now].Num += val;
return;
}
int Mid = (l + r) >> 1;
Modify(Tr[Now].l, l, Mid, lx, rx, val), Modify(Tr[Now].r, Mid + 1, r, lx, rx, val);
}
void Modify(int v, int val) {
int c = S[v] - '0', l, r;
if (c == 0) l = 0, r = P - 1; else l = P, r = N - 1;
l = ((l % N - 1ll * A * v % N) % N + N) % N;
r = ((r % N - 1ll * A * v % N) % N + N) % N;
if (l <= r) Modify(Root, 0, N - 1, l, r, val); else
Modify(Root, 0, N - 1, l, N - 1, val), Modify(Root, 0, N - 1, 0, r, val);
}
int main() {
scanf("%d%d%d%d%d\n", &N, &A, &B, &P, &M);
scanf("%s", S);
Root = tot = 1;
for (int i = 0; i < M; i ++) Modify(i, 1);
scanf("%d", &Q);
for (int i = 1; i <= Q; i ++) {
int v;
scanf("\n%s%d", C + 1, &v);
if (C[1] == 'Q') printf("%d\n", M - Query(Root, 0, N - 1, Calc(v))); else {
Modify(v, -1);
S[v] = (S[v] == '0') ? '1' : '0';
Modify(v, 1);
}
}
}