2200左右的DS题单
字典树
一眼转换为前缀和形式, 然后字典树计数即可

#include <bits/stdc++.h> using namespace std; #define endl "\n" typedef long long ll; const int N = 1e6 + 100; int Trie[N * 32][2], cnt, n, k; int num[N * 32]; ll ans; void insert(int x) { int now = 0; for (int i = 30; i >= 0; i--) { int j = x >> i & 1; if (!Trie[now][j]) Trie[now][j] = ++cnt; now = Trie[now][j]; num[now]++; } } void query(int x) { int now = 0; for (int i = 30; i >= 0; i--) { int j = x >> i & 1; if (k >> i & 1) { if(!Trie[now][!j]) return; now = Trie[now][!j]; } else { ans += num[Trie[now][!j]]; if(!Trie[now][j]) return; now = Trie[now][j]; } } ans += num[now]; } void solve() { cin >> n >> k; ll now = 0; insert(0); for(int i = 1; i <= n; i++) { int x; cin >> x; now ^= x; insert(now); query(now); } cout << ans << endl; } signed main() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); // int T = 1; cin >> T; // while (T--) solve(); solve(); return 0; }
还是 01 trie 树, 和上一题基本上一模一样

// LUOGU_RID: 142877460 #include <bits/stdc++.h> using namespace std; #define endl "\n" typedef long long ll; const int N = 1e5 + 100; int Trie[N * 32][2], cnt, n, p, l; int num[N * 32]; ll ans; void insert(int x) { int now = 0; for (int i = 31; i >= 0; i--) { int j = x >> i & 1; if (!Trie[now][j]) Trie[now][j] = ++cnt; now = Trie[now][j]; num[now]++; } } void erase(int x) { int now = 0; for (int i = 31; i >= 0; i--) { int j = x >> i & 1; now = Trie[now][j]; num[now]--; } } void query() { int now = 0; for (int i = 31; i >= 0; i--) { int j = p >> i & 1; if (l >> i & 1) { ans += num[Trie[now][j]]; if(!num[Trie[now][!j]]) return; now = Trie[now][!j]; } else { if(!num[Trie[now][j]]) return; now = Trie[now][j]; } } } void solve() { int q; cin >> q; while (q--) { int op; cin >> op; if (op == 1) { int x; cin >> x; insert(x); } else if (op == 2) { int x; cin >> x; erase(x); } else { cin >> p >> l; ans = 0; query(); cout << ans << endl; } } } signed main() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); // int T = 1; cin >> T; // while (T--) solve(); solve(); return 0; }
线段树/树状数组
类似于 HH的项链 的离线做法
首先我们可以知道对于一个点计算距离真正有用的一定是前一个点(因为要求最短距离)
那么我们可以用线段树维护一个
为了保证在区间 [ l, r ] 之间我们离线下来每个询问, 从 1 到 n 的处理每个询问
每到一个点 i 我们修改

#include <bits/stdc++.h> using namespace std; #define endl "\n" typedef long long ll; const int N = 5e5 + 100; int a[N], pre[N], pos[N], Seg[N << 2], res[N]; vector<int> vec; vector<array<int, 2>> g[N]; int get_idx(int x) { return lower_bound(vec.begin(), vec.end(), x) - vec.begin() + 1; } void pushup(int id) { Seg[id] = min(Seg[id << 1], Seg[id << 1 | 1]); } void modify(int id, int l, int r, int pos, int v) { if (l == r) { Seg[id] = v; return; } int mid = (l + r) >> 1; if (pos <= mid) modify(id << 1, l, mid, pos, v); else modify(id << 1 | 1, mid + 1, r, pos, v); pushup(id); } int query(int id, int l, int r, int x, int y) { if (x <= l && y >= r) return Seg[id]; int mid = (l + r) >> 1, ans = INT_MAX; if (x <= mid) ans = min(ans, query(id << 1, l, mid, x, y)); if(y > mid) ans = min(ans, query(id << 1 | 1, mid + 1, r, x, y)); return ans; } void solve() { int n, m; cin >> n >> m; for (int i = 1; i <= 4 * N; i++) Seg[i] = INT_MAX; for (int i = 1; i <= n; i++) { cin >> a[i]; vec.push_back(a[i]); } for (int i = 1; i <= m; i++) { int l, r; cin >> l >> r; g[r].push_back({l, i}); } sort(vec.begin(),vec.end()); vec.erase(unique(vec.begin(), vec.end()), vec.end()); for(int i = 1; i <= n; i++) { int id = get_idx(a[i]); pre[i] = pos[id]; pos[id] = i; // cout << i << ' ' << pre[i] << endl; } for(int r = 1; r <= n; r++) { if(pre[r]) modify(1, 1, n, pre[r], r - pre[r]); for(auto [l, id] : g[r]) { // cout << l << ' ' << r << endl; res[id] = query(1, 1, n, l, r); } } for(int i = 1; i <= m; i++) { // cout << res[i] << endl; cout << (res[i] == INT_MAX ? -1 : res[i]) << endl; } } signed main() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); // int T = 1; cin >> T; // while (T--) solve(); solve(); return 0; }
用线段树维护一个类似于区间合并的 dp
参考 : Codeforces Hello 2024 ABCDF1F2 讲解
把每个区间多出来的水, 多出来的体积, 答案都维护出来
转移时一定是从左边多出来的水转移到右边多出来的体积

#include<bits/stdc++.h> using namespace std; #define endl "\n" #define int long long typedef long long ll; const int N = 5e5 + 100; int a[N], b[N], c[N]; struct node { int s, r, d; } Seg[N << 2]; void pushup(int id) { int v = min(Seg[id << 1].s, Seg[id << 1 | 1].r); Seg[id].d = Seg[id << 1].d + Seg[id << 1 | 1].d + v; Seg[id].s = Seg[id << 1].s + Seg[id << 1 | 1].s - v; Seg[id].r = Seg[id << 1].r + Seg[id << 1 | 1].r - v; } void modify(int id, int l, int r, int pos, int v1, int v2) { if(l == r) { Seg[id].d = min(v1, v2); Seg[id].s = max(0ll, v1 - v2); Seg[id].r = max(0ll, v2 - v1); return; } int mid = (l + r) >> 1; if(pos <= mid) modify(id << 1, l, mid, pos, v1, v2); else modify(id << 1 | 1, mid + 1, r, pos, v1, v2); pushup(id); } void solve() { int n, q; cin >> n >> q; for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 1; i <= n; i++) cin >> b[i]; for (int i = 1; i < n; i++) cin >> c[i]; for (int i = 1; i <= n; i++) modify(1, 1, n, i, a[i], b[i]); while (q--) { int p, x, y, z; cin >> p >> x >> y >> z; modify(1, 1, n, p, x, y); cout << Seg[1].d << endl; } } signed main() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); // int T = 1; cin >> T; // while (T--) solve(); solve(); return 0; }
权值线段树(平衡树)优化 dp
朴素dp思路就是
满足
找

#include <bits/stdc++.h> using namespace std; #define endl "\n" #define int long long typedef long long ll; const int N = 1e5 + 100; int a[N], f[N], pre[N]; vector<ll> vec; pair<int, int> Seg[N << 4]; int get_idx(int x) { return lower_bound(vec.begin(), vec.end(), x) - vec.begin() + 1; } pair<int, int> operator + (const pair<int, int> &l, const pair<int, int> &r) { pair<int, int> ans; auto [v1, pos1] = l; auto [v2, pos2] = r; if (v1 > v2) ans = l; else ans = r; return ans; } void pushup(int id) { Seg[id] = Seg[id << 1] + Seg[id << 1 | 1]; } void modify(int id, int l, int r, int pos, int v) { if (l == r) { Seg[id] = {v, pos}; return; } int mid = (l + r) >> 1; if (pos <= mid) modify(id << 1, l, mid, pos, v); else modify(id << 1 | 1, mid + 1, r, pos, v); pushup(id); } pair<int, int> query(int id, int l, int r, int x, int y) { if (x <= l && y >= r) return Seg[id]; int mid = (l + r) >> 1; pair<int, int> tl, tr; tl = tr = {INT_MIN, 0}; if(x <= mid) tl = query(id << 1, l, mid, x, y); if(y > mid) tr = query(id << 1 | 1, mid + 1, r, x, y); return tl + tr; } void solve() { int n, d; cin >> n >> d; for (int i = 1; i <= n; i++) { cin >> a[i]; vec.push_back(a[i]); vec.push_back(a[i] + d); vec.push_back(a[i] - d); } vec.push_back(0); vec.push_back(1e15 + 100); sort(vec.begin(),vec.end()); vec.erase(unique(vec.begin(), vec.end()), vec.end()); int sz = vec.size(), maxn = 0, mpos = -1; map<ll, int> vis; for (int i = 1; i <= n; i++) { int idl = get_idx(a[i] - d); int idr = get_idx(a[i] + d); int id = get_idx(a[i]); pair<int, int> l = query(1, 1, sz, 1, idl); pair<int, int> r = query(1, 1, sz, idr, sz); pair<int, int> ans = l + r; auto [v, pos] = ans; f[i] = v + 1; pre[i] = vis[pos]; vis[id] = i; if(f[i] > maxn) maxn = f[i], mpos = i; modify(1, 1, sz, id, f[i]); } // for(int i = 1; i <= n; i++) cout << i << ' ' << pre[i] << endl; vector<int> ans; cout << maxn << endl; ans.push_back(mpos); while (pre[mpos]) { mpos = pre[mpos]; ans.push_back(mpos); } reverse(ans.begin(), ans.end()); for(auto i : ans) cout << i << ' '; cout << endl; } signed main() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); // int T = 1; cin >> T; // while (T--) solve(); solve(); return 0; }
纯纯大水题, 就类似于一个维护最多 1 的个数线段树的 pushup 操作维护出 maxn , l_maxn , r_maxn 从左到右合并就行

#include <bits/stdc++.h> using namespace std; #define endl "\n" #define int long long typedef long long ll; const int N = 300000; int ord[N], mx[N], lmx[N], rmx[N], sum[N]; int Ansmx[N], Anslmx[N], Ansrmx[N], Anssum[N]; void pushup(int id) { int l = id, r = ord[id + 1]; Ansmx[id + 1] = max({Ansmx[id], mx[r], Ansrmx[id] + lmx[r]}); Anslmx[id + 1] = max(Anslmx[id], Anssum[id] + lmx[r]); Ansrmx[id + 1] = max(rmx[r], sum[r] + Ansrmx[id]); Anssum[id + 1] = Anssum[id] + sum[r]; } void solve() { int n, m; cin >> n >> m; vector<vector<int>> a(n + 1); memset(mx, 128, sizeof(mx)); memset(lmx, 128, sizeof(lmx)); memset(rmx, 128, sizeof(rmx)); for (int i = 1; i <= n; i++) { int sz; cin >> sz; a[i].resize(sz + 1); for (int j = 1; j <= sz; j++) cin >> a[i][j]; vector<int> f(sz + 1); for (int j = 1; j <= sz; j++) { sum[i] += a[i][j]; f[j] = max(a[i][j], f[j - 1] + a[i][j]); mx[i] = max(mx[i], f[j]); lmx[i] = max(lmx[i], sum[i]); } int now = 0; for (int j = sz; j >= 1; j--) { now += a[i][j]; rmx[i] = max(rmx[i], now); } } for (int i = 1; i <= m; i++) cin >> ord[i]; Ansmx[1] = mx[ord[1]]; Anslmx[1] = lmx[ord[1]]; Ansrmx[1] = rmx[ord[1]]; Anssum[1] = sum[ord[1]]; for (int i = 1; i < m; i++) pushup(i); cout << Ansmx[m] << endl; } signed main() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); // int T = 1; cin >> T; // while(T--) solve(); solve(); return 0; }
第一次自己独立写出来 2200 的题,但是写完以后看了下题解, 发现好像写的有点复杂了
做法 : 首先这种题肯定是需要从位置的后面往前面维护的, 那么我们只需要维护一下每个点能到的最右边的点就行
假定对于一块牌倒下去可以覆盖的区间是 [ l , r ] 那么我们只需要知道这段区间中所有的牌能覆盖到的最右边端点是哪(查询区间 max 的线段树), 假定为 nowr 那么区间 [ l, nowr ] 就是统计答案的区间 (可以用树状数组计数)
所以一颗线段树 + 树状数组 + 离散化 即可通过本题

#include <bits/stdc++.h> using namespace std; #define endl "\n"; typedef long long ll; const int N = 3e5 + 10; template <typename T> struct BIT { T tr[N]; int n; void init(int n_){ n = n_; for(int i = 0; i <= n; i ++) tr[i] = 0; } inline int lowbit(int x) {return x & -x;} void add(int x, T v){ for(int i = x; i <= n; i += lowbit(i)) tr[i] += v; } T sum(int x){ T res = 0; for(int i = x; i > 0; i -= lowbit(i)) res += tr[i]; return res; } // 查询最大位置pos,使得1 ~ pos 和小于等于s,a1 + a2 + ....apos <= s int query(T s){ int pos = 0; for(int i = 20; i >= 0; i --){ if(pos + (1 << i) <= n && tr[pos + (1 << i)] <= s){ pos += (1 << i); s -= tr[pos]; } } return pos; } T sum(int l, int r){ return sum(r) - sum(l - 1);} void add(int l, int r, T v) {add(l, v); add(r + 1, -v);}; }; struct NODE { int x, h, id; } a[N]; bool cmp(NODE na, NODE nb) { return na.x < nb.x; } vector<int> vec; int ans[N]; BIT<int> T; int get_idx(int x) { return lower_bound(vec.begin(), vec.end(), x) - vec.begin() + 1; } int Seg[N << 2]; void pushup(int id) { Seg[id] = max(Seg[id << 1], Seg[id << 1 | 1]); } void modify(int id, int l, int r, int pos, int v) { if (l == r) { Seg[id] = v; return; } int mid = l + r >> 1; if (pos <= mid) modify(id << 1, l, mid, pos, v); else modify(id << 1 | 1, mid + 1, r, pos, v); pushup(id); } int query(int id, int l, int r, int x, int y) { if (x <= l && y >= r) return Seg[id]; int mid = l + r >> 1, res = INT_MIN; if (x <= mid) res = max(res, query(id << 1, l, mid, x, y)); if (y > mid) res = max(res, query(id << 1 | 1, mid + 1, r, x, y)); return res; } void solve() { int n; cin >> n; for (int i = 1; i <= n; i++) { int x, h; cin >> x >> h; a[i] = {x, h, i}; vec.push_back(x); vec.push_back(x + h - 1); vec.push_back(x + 1); } sort(a + 1, a + 1 + n, cmp); sort(vec.begin(),vec.end()); vec.erase(unique(vec.begin(), vec.end()), vec.end()); int sz = vec.size(); T.init(sz + 10); for (int i = n; i >= 1; i--) { auto [x, h, id] = a[i]; int pos = get_idx(x), posl = get_idx(x + 1), posr = get_idx(x + h - 1); T.add(pos, 1); int r = query(1, 1, sz, posl, posr); ans[id] = T.sum(pos, max(r, posr)); modify(1, 1, sz, pos, max(posr, r)); // cout << x << ' ' << vec[max(r, posr) - 1] << endl; } for (int i = 1; i <= n; i++) cout << ans[i] << ' '; } int main() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); // int T; cin >> T; // while (T--) solve(); solve(); return 0; }
首先显而易见,对于某个值 x 当到某个临界点时会全是一种值然后就是彼此之间循环加(变成一个查询 k 大的问题)
对于临界点的处理,我们把到达某个点全变成该点边权代价处理出来, 记代价为 val ,那么我们临界点的值 v 一定是 val [ i + 1] >= v > val [ i ]
我们离线下来询问, 从小到大加点, 再用权值线段树二分查询 k 大就行

#include <bits/stdc++.h> using namespace std; #define endl "\n" #define int long long typedef long long ll; const int N = 5e5 + 100; int cnt[N], Q[N], Seg[N * 4]; void pushup(int id) { Seg[id] = Seg[id * 2] + Seg[id * 2 + 1]; } void modify(int id, int l, int r, int pos, int v) { if (l == r) { Seg[id] = v; return; } int mid = l + r >> 1; if (pos <= mid) modify(id * 2, l, mid, pos, v); else modify(id * 2 + 1, mid + 1, r, pos, v); pushup(id); } int query(int id, int l, int r, int k) { if (l == r) return l; int mid = l + r >> 1; if (Seg[id * 2] >= k) return query(id * 2, l, mid, k); else return query(id * 2 + 1, mid + 1, r, k - Seg[id * 2]); } void solve() { int n, m, q; cin >> n >> m >> q; vector<array<int, 2>> a; map<ll, int> que, ans; for (int i = 1; i <= n; i++) { int x; cin >> x; cnt[x]++; } a.push_back({0, 0}); for (int i = 1; i <= m; i++) a.push_back({cnt[i], i}); sort(a.begin() + 1, a.end()); vector<ll> pre(m + 1, 0), val(m + 1, 0); for (int i = 1; i <= m; i++) { pre[i] = pre[i - 1] + a[i][0]; val[i] = a[i][0] * i - pre[i]; } val.push_back(LLONG_MAX); for (int i = 1; i <= q; i++) { cin >> Q[i]; que[Q[i]] = 1; } int p = 0; for (auto [x, y] : que) { int id = lower_bound(val.begin() + 1, val.end(), x - n) - val.begin() - 1; if (id <= 0) id = 0; for (int i = p + 1; i <= id; i++) modify(1, 1, m, a[i][1], 1); p = id; ans[x] = query(1, 1, m, ((x - val[id] - n) % id) ? (x - val[id] - n) % id : id); } for (int i = 1; i <= q; i++) { cout << ans[Q[i]] << endl; } } signed main() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); // int T; cin >> T; // while (T--) solve(); solve(); return 0; }
扫描线好题,codeforce 一些板刷 - zhujio 3.12

#include <bits/stdc++.h> using namespace std; #define endl "\n" #define int long long typedef long long ll; const int N = 2e5 + 100; vector<array<int, 2>> op[N]; vector<array<int, 3>> que[N]; struct node { int sum, pre, suf, val; } Seg[N * 4]; node operator + (const node &l, const node &r) { node ans; ans.sum = l.sum + r.sum; ans.pre = max(l.pre, l.sum + r.pre); ans.suf = max(r.suf, r.sum + l.suf); ans.val = max({l.val, r.val, l.suf + r.pre}); return ans; } void pushup(int id) { Seg[id] = Seg[id * 2] + Seg[id * 2 + 1]; } void modify(int id, int l, int r, int pos, int v) { if (l == r) { Seg[id].sum += v; Seg[id].pre += v; Seg[id].suf += v; Seg[id].val += v; return; } int mid = l + r >> 1; if (pos <= mid) modify(id * 2, l, mid, pos, v); else modify(id * 2 + 1, mid + 1, r, pos, v); pushup(id); } node query(int id, int l, int r, int x, int y) { if (x <= l && y >= r) return Seg[id]; int mid = l + r >> 1; if (x > mid) return query(id * 2 + 1, mid + 1, r, x, y); else if (y <= mid) return query(id * 2, l, mid, x, y); else return query(id * 2, l, mid, x, mid) + query(id * 2 + 1, mid + 1, r, mid + 1, y); } void solve() { int n, m; cin >> n >> m; for (int i = 1; i <= m; i++) { int l, r, v; cin >> l >> r >> v; op[l].push_back({v, i}); op[r + 1].push_back({-v, i}); } int q; cin >> q; for (int i = 1; i <= q; i++) { int pos, l, r; cin >> pos >> l >> r; que[pos].push_back({l, r, i}); } vector<int> ans(q + 1); for (int i = 1; i <= n; i++) { for (auto [v, id] : op[i]) modify(1, 1, m, id, v); for (auto [l, r, id] : que[i]) ans[id] = query(1, 1, m, l, r).val; } for (int i = 1; i <= q; i++) cout << ans[i] << endl; } signed main() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); solve(); return 0; }
codeforce 一些板刷 3.12

#include <bits/stdc++.h> using namespace std; #define endl "\n" #define int long long typedef long long ll; const int N = 1e6 + 100; array<int, 3> op[N]; vector<int> g[N]; template <typename T> struct BIT { T tr[N]; int n; void init(int n_) { n = n_; for(int i = 0; i <= n; i++) tr[i] = 0; } int lowbit(int x) {return x & -x;} void add(int x, T v){ for(int i = x; i <= n; i += lowbit(i)) tr[i] += v; } T sum(int x) { T res = 0; for(int i = x; i > 0; i -= lowbit(i)) res += tr[i]; return res; } // 查询最大位置pos,使得1 ~ pos 和小于等于s,a1 + a2 + .... + apos <= s int query(T s){ int pos = 0; for(int i = 20; i >= 0; i--){ if(pos + (1 << i) <= n && tr[pos + (1 << i)] <= s){ pos += (1 << i); s -= tr[pos]; } } return pos; } T sum(int l, int r) {return sum(r) - sum(l - 1);} void add(int l, int r, T v) {add(l, v); add(r + 1, -v);} }; int L[N], R[N], dfn; void dfs(int x, int fa) { L[x] = ++dfn; for (auto y : g[x]) { if (y == fa) continue; dfs(y, x); } R[x] = dfn; } BIT<int> T; void solve() { int q; cin >> q; int sz = 1; dfn = 0; for (int i = 1; i <= q; i++) { int opt; cin >> opt; if (opt == 1) { int x; cin >> x; op[i] = {opt, sz + 1, 0}; g[x].push_back(sz + 1); sz++; } else { int x, v; cin >> x >> v; op[i] = {opt, x, v}; } } dfs(1, 1); vector<int> ans(sz + 1); T.init(sz + 100); for (int i = q; i >= 1; i--) { auto [opt, x, y] = op[i]; if (opt == 1) { ans[x] = T.sum(L[x]); } else { T.add(L[x], R[x], y); } } ans[1] = T.sum(1); for (int i = 1; i <= sz; i++) cout << ans[i] << " \n"[i == sz]; for (int i = 0; i <= sz; i++) g[i].clear(), L[i] = R[i] = 0; } signed main() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); int T; cin >> T; while (T--) solve(); return 0; }
哈希
首先观察到只会有两种串, 那么我们去枚举前缀第一个串的长度, 那么对于另外一个串长度是可以算出来的(写的时候犯病了,一直在想另外一个串怎么处理)
那么这时我们其实两个串都知道了,只需要去遍历一遍 01 串 check 就行, 这个复杂度看起来是非常 O( | s | * | t | ) 的
但是我们枚举玩第一串长度后, 剩下长度必须与另外一个串出现次数是整除关系, 似乎可以剪枝掉很多? 复杂度有点不太懂怎么证明...

#include <bits/stdc++.h> using namespace std; #define endl "\n"; #define int long long typedef long long ll; //字符串hash , 使用时应在字符串首补一个符号 struct Hash { vector<int> hs1, hs2, pn1, pn2; int length, base = 131, p1 = 1222827239, p2 = 1610612741; public: explicit Hash(const string& s) //传入字符串初始下标应为1 { length = (int)s.length() - 1; hs1.resize(length + 1); hs2.resize(length + 1); pn1.resize(length + 1); pn2.resize(length + 1); pn1[0] = pn2[0] = 1; for (int i = 1; i <= length; i++) { hs1[i] = (hs1[i - 1] * 1ll * base + s[i]) % p1; hs2[i] = (hs2[i - 1] * 1ll * base + s[i]) % p2; pn1[i] = pn1[i - 1] * 1ll * base % p1; pn2[i] = pn2[i - 1] * 1ll * base % p2; } } int gethash1(int l, int r) { if(l > r) return 0; return (hs1[r] - hs1[l - 1] * 1ll * pn1[r - l + 1] % p1 + p1) % p1; } int gethash2(int l, int r) { if(l > r) return 0; return (hs2[r] - hs2[l - 1] * 1ll * pn2[r - l + 1] % p2 + p2) % p2; } }; void solve() { string s1, s2; cin >> s1 >> s2; int n1 = s1.size(), n2 = s2.size(); s1 = " " + s1; s2 = " " + s2; Hash hash(s2); int cnt0 = 0, cnt1 = 0; for (int i = 1; i <= n1; i++) { cnt0 += s1[i] == '0'; cnt1 += s1[i] == '1'; } int ans = 0; for (int len = 1; len < n2; len++) { if (len * (s1[1] == '1' ? cnt1 : cnt0) >= n2) continue; int del = n2 - len * (s1[1] == '1' ? cnt1 : cnt0); if (del % (s1[1] == '1' ? cnt0 : cnt1)) continue; int tot = del / (s1[1] == '1' ? cnt0 : cnt1); int val0 = -1, val1 = -1, v0 = -1, v1 = -1, l = 1, r; bool ok = true; for (int i = 1; i <= n1; i++) { if (s1[i] == s1[1]) { r = l + len - 1; if (val0 == -1) val0 = hash.gethash1(l, r), v0 = hash.gethash2(l, r); else { if (val0 != hash.gethash1(l, r) || v0 != hash.gethash2(l, r)) { ok = false; break; } } l = r + 1; } else { r = l + tot - 1; if (val1 == -1) val1 = hash.gethash1(l, r), v1 = hash.gethash2(l, r); else { if (val1 != hash.gethash1(l, r) || v1 != hash.gethash2(l, r)) { ok = false; break; } } l = r + 1; } } if (ok && (val0 != val1 || v0 != v1)) ans++; } cout << ans << endl; } signed main() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); // int T; cin >> T; // while (T--) solve(); solve(); return 0; }
根号分治
根号分治 - zhujio 哈希冲突那题基本上一模一样

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】