CF1043G Speckled Band
CF1043G Speckled Band
给定字符串 ,每次询问 ,将子串 划分为若干段使得至少有两段相同,求拆分后 本质不同的段 的最小个数。
结果为 当且仅当子串中每个字符只出现一次,否则可以发现 。
令 ,以下 表示字符串。
- ,此时子串为 ,枚举 的约数 , 有长度为 的循环节的充要条件为 。
- ,子串为 ,前者可以求出子串的最短 判断;对于后两者,考虑求出 表示以 为 开头/结尾 的最短 串长度,那么 。
- ,子串为 ,对于前二者,只需要判断 中是否有字符出现超过一次(以它们为 );后者只需要判断 。
- 否则 。
求最短 :
- 首先枚举长度为 的 ,否则最短 与 的后缀排名不超过 。
- 考虑反证法,若 且与 的后缀排名超过 ,则可以证明有更短的 ,与要求矛盾。
求 :
- 方法与 NOI2016 优秀的拆分 类似。
- 考虑求长度为 的 串,将原串每 位设置关键点,则长为 的 串一定经过且只经过两个关键点。
- 可以以关键点将 分为 和 。
- 求出相邻关键点的 和 ,那么形成 串的充要条件为 ,开头区间为 。
- 求 类似。
复制代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
using namespace std;
void read(int &x) {
char ch = getchar(); x = 0;
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + ch - 48, ch = getchar();
}
char ch[N + 1];
int n;
struct HASH {
int h[N + 1], mi[N + 1], inv[N + 1], p, mo;
int pw(int x, int k) {
int res = 1;
while (k) {
if (k & 1) res = 1ll * res * x % mo;
x = 1ll * x * x % mo;
k >>= 1;
}
return res;
}
void build(int x, int y) {
mo = x, p = y;
mi[0] = 1;
fo(i, 1, n) mi[i] = 1ll * mi[i - 1] * p % mo;
inv[n] = pw(mi[n], mo - 2);
fd(i, n, 1)
inv[i - 1] = 1ll * inv[i] * p % mo;
fo(i, 1, n)
h[i] = (h[i - 1] + 1ll * (ch[i] - 'a' + 1) * mi[i] % mo) % mo;
}
int hash(int l, int r) {
return 1ll * (h[r] - h[l - 1] + mo) % mo * inv[l] % mo;
}
} h1, h2;
bool check(int l, int r, int x, int y) {
return h1.hash(l, r) == h1.hash(x, y) && h2.hash(l, r) == h2.hash(x, y);
}
int Log[N + 1];
struct SA {
int sa[N + 1], rk[N + 1], ht[N + 1], id[N + 1], oldrk[N << 1], buc[N + 1], px[N + 1], ft[N + 1][L + 1];
int sk;
void mysort() {
fill(buc, buc + 1 + sk, 0);
fo(i, 1, n) ++ buc[ px[i] = rk[id[i]] ];
fo(i, 1, sk) buc[i] += buc[i - 1];
fd(i, n, 1) sa[ buc[px[i]] -- ] = id[i];
}
bool pd(int x, int y, int z) { return oldrk[x] == oldrk[y] && oldrk[x + z] == oldrk[y + z]; }
void build(char ch[]) {
Mes(rk, 0), Mes(oldrk, 0);
sk = 26;
fo(i, 1, n) rk[ id[i] = i ] = ch[i] - 'a' + 1;
mysort();
for (int w = 1, p = 0; w <= n; w <<= 1, p = 0) {
fo(i, n - w + 1, n) id[ ++ p ] = i;
fo(i, 1, n) if (sa[i] > w)
id[ ++ p ] = sa[i] - w;
mysort();
mcp(oldrk, rk);
sk = 0;
fo(i, 1, n)
rk[sa[i]] = pd(sa[i], sa[i - 1], w) ? sk : ++ sk;
if (sk == n) {
fo(i, 1, n) sa[rk[i]] = i;
break;
}
}
sk = 0;
fo(i, 1, n) {
if (sk) -- sk;
while (ch[i + sk] == ch[sa[rk[i] - 1] + sk])
++ sk;
ht[rk[i]] = sk;
}
fo(i, 1, n) ft[i][0] = ht[i];
fo(j, 0, L - 1) fo(i, 1, n)
ft[i][j + 1] = (i + (1 << j) <= n) ? min(ft[i][j], ft[i + (1 << j)][j]) : ft[i][j];
}
int dt;
int get(int l, int r) {
l = rk[l], r = rk[r];
if (l > r) swap(l, r);
if (++ l == r) return ft[l][0];
dt = Log[r - l + 1];
return min(ft[l][dt], ft[r - (1 << dt) + 1][dt]);
}
} s1, s2;
struct Tree {
int vl[N << 2];
Tree() { Mes(vl, 0x3f); }
void Add(int t, int l, int r, int x, int y, int k, int lz) {
if (lz < vl[t]) vl[t] = lz;
if (x <= l && r <= y) {
vl[t] = k; return;
}
int mid = l + r >> 1;
if (x <= mid) Add(ls, l, mid, x, y, k, vl[t]);
if (y > mid) Add(rs, mid + 1, r, x, y, k, vl[t]);
}
void fil(int t, int l, int r, int lz, int at[]) {
if (lz < vl[t]) vl[t] = lz;
if (l == r) {
at[l] = vl[t]; return;
}
int mid = l + r >> 1;
fil(ls, l, mid, vl[t], at), fil(rs, mid + 1, r, vl[t], at);
}
} t1, t2;
int gt[N + 1][L + 1], dl[N + 1], dr[N + 1], sc[N + 1][26];
const int inf = 0x3f3f3f3f;
int sqn;
void Init() {
Log[1] = 0;
fo(i, 2, n) Log[i] = Log[i >> 1] + 1;
h1.build(998244353, 37);
h2.build(1000000007, 29);
s1.build(ch);
fd(i, (n >> 1), 1)
swap(ch[i], ch[n - i + 1]);
s2.build(ch);
fd(i, (n >> 1), 1)
swap(ch[i], ch[n - i + 1]);
int l, r, lcp, lcs, dlen, pl, pr;
fd(len, (n >> 1), 1) {
fd(k, (n / len) - 1, 1) {
l = len * k, r = len * (k + 1);
lcs = s1.get(l, r);
lcp = s2.get(n - l + 1, n - r + 1);
if (lcp + lcs > len) {
lcp = min(lcp, len), lcs = min(lcs, len);
dlen = lcp + lcs - len - 1;
t1.Add(1, 1, n, l - lcp + 1, l - lcp + 1 + dlen, (len << 1), inf);
t2.Add(1, 1, n, r + lcs - 1 - dlen, r + lcs - 1, (len << 1), inf);
}
}
}
t1.fil(1, 1, n, inf, dl), t2.fil(1, 1, n, inf, dr);
fo(i, 1, n) {
fo(j, 0, 25) sc[i][j] = sc[i - 1][j];
++ sc[i][ch[i] - 'a'];
}
fo(i, 1, n) gt[i][0] = i + dl[i] - 1;
fo(j, 0, L - 1) fo(i, 1, n)
gt[i][j + 1] = (i + (1 << j) <= n) ? min(gt[i][j], gt[i + (1 << j)][j]) : gt[i][j];
sqn = sqrt(n);
}
bool pd0(int l, int r) {
fo(i, 0, 25) if (sc[r][i] - sc[l - 1][i] > 1)
return 0;
return 1;
}
int len, sq;
bool pd1(int l, int r) {
len = r - l + 1, sq = sqrt(len);
if (check(l, r - 1, l + 1, r)) return 1;
fo(i, 2, sq) if (len % i == 0)
if (check(l, r - i, l + i, r) || check(l, r - len / i, l + len / i, r))
return 1;
return 0;
}
int min_ht;
bool pd2(int l, int r) {
len = r - l + 1;
if (dl[l] <= len || dr[r] <= len)
return 1;
fd(i, min(sqn, (len >> 1)), 1) if (check(l, l + i - 1, r - i + 1, r))
return 1;
if (sqn >= (len >> 1)) return 0;
min_ht = s1.ht[s1.rk[l]];
fd(i, s1.rk[l] - 1, s1.rk[l] - sqn + 1) {
if (i < 1) break;
if ((l + r >> 1) < s1.sa[i] && s1.sa[i] <= r && s1.sa[i] + min_ht > r)
return 1;
min_ht = min(min_ht, s1.ht[i]);
}
min_ht = len;
fo(i, s1.rk[l] + 1, s1.rk[l] + sqn - 1) {
if (i > n) break;
min_ht = min(min_ht, s1.ht[i]);
if ((l + r >> 1) < s1.sa[i] && s1.sa[i] <= r && s1.sa[i] + min_ht > r)
return 1;
}
return 0;
}
bool pd3(int l, int r) {
return (sc[r][ch[l] - 'a'] - sc[l][ch[l] - 'a'] > 0) || (sc[r - 1][ch[r] - 'a'] - sc[l - 1][ch[r] - 'a'] > 0);
}
int dx;
int get_Min_dl(int l, int r) {
if (l == r) return gt[l][0];
dx = Log[r - l + 1];
return min(gt[l][dx], gt[r - (1 << dx) + 1][dx]);
}
int main() {
scanf("%d\n%s", &n, ch + 1);
Init();
int T, l, r; read(T);
while (T --) {
read(l), read(r);
if (pd0(l, r))
puts("-1");
else
if (pd1(l, r))
puts("1");
else
if (pd2(l, r))
puts("2");
else
if (pd3(l, r) || get_Min_dl(l, r) <= r)
puts("3");
else
puts("4");
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步