练习选讲(2023.5-6)
5 月
NOIP 2018 模拟 Day2:
ending:给定一棵
题解:
若
那么
时间复杂度
点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
#define int long long
const int N = 1e5+10;
int n, ans, p[N], siz[N];
int check(int w) {
while (w) {
if (w % 10 != 4 && w % 10 != 7) return 0;
w /= 10;
}
return 1;
}
int find(int x) {
if (p[x] != x) return find(p[x]);
return x;
}
void merge(int u, int v) {
int fu = find(u), fv = find(v);
if (fu == fv) return ;
siz[fv] += siz[fu], p[fu] = fv;
return ;
}
signed main() {
// freopen("ending.in", "r", stdin);
// freopen("ending.out", "w", stdout);
scanf("%lld", &n);
for (int i = 1; i <= n; ++i) p[i] = i, siz[i] = 1;
int u, v, w;
for (int i = 1; i < n; ++i) {
scanf("%lld%lld%lld", &u, &v, &w);
w = check(w);
if (!w) merge(u, v); // 分割成内部不能到达的连通块
}
for (int i = 1; i <= n; ++i) {
if (i != find(i) || siz[i] < 2) continue ;
int size = siz[i];
ans += size*(size-1)*(size-2) + size*(size-1)*(n-size)*2;
}
printf("%lld\n", n*(n-1)*(n-2)-ans);
return 0;
}
/*
10
1 2 8
1 3 7
3 4 47
5 7 23
4 6 4
6 10 747
8 6 57
9 3 447
9 5 88
566
*/
6 月
6.9:
P1486 [NOI2004] 郁闷的出纳员:* 平衡树(蓝)
题解:
用一个变量
对于插入操作 I k
,向平衡树中插入一个数
对于全局加法操作 A k
,直接将
对于全局减法操作 S k
,将
对于查询排名操作 F k
,在平衡树上二分查找即可。若遍历到
用 fhq-treap 实现,时间复杂度
点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 3e5+10;
int n, minl, ans, delta, idx, root; // delta 表示所有员工的工资变化量
struct Node {
int l, r;
int val, key; // BST, 堆
int size;
} tree[N];
void pushup(int u) {
tree[u].size = tree[tree[u].l].size + tree[tree[u].r].size + 1;
}
int newNode(int v) {
++ idx;
tree[idx].l = tree[idx].r = 0;
tree[idx].val = v, tree[idx].key = rand();
tree[idx].size = 1;
return idx;
}
void split(int p, int v, int &x, int &y) { // 按 v 分裂子树, 左子树小于等于x, 右子树大于x
if (!p) {x = y = 0; return ;}
if (tree[p].val <= v) {
x = p;
split(tree[p].r, v, tree[p].r, y);
} else {
y = p;
split(tree[p].l, v, x, tree[p].l);
}
pushup(p);
}
int merge(int x, int y) { // 合并子树, x中的值均小于y中的值
if (!x || !y) return x + y;
if (tree[x].key <= tree[y].key) {
tree[x].r = merge(tree[x].r, y);
pushup(x); return x;
} else {
tree[y].l = merge(x, tree[y].l);
pushup(y); return y;
}
}
void insert(int v) { // 插入 v
int x, y, z;
split(root, v, x, z);
y = newNode(v);
root = merge(merge(x, y), z);
}
void del(int v) { // 删除小于v的数
int x, y;
split(root, v-1, x, y);
ans += tree[x].size;
root = y;
}
int get_num(int p, int k) { // 在以p为根的子树内查询第 k 大数
if (!p) return -1;
if (tree[tree[p].r].size >= k) return get_num(tree[p].r, k);
if (tree[tree[p].r].size+1 == k) return tree[p].val;
return get_num(tree[p].l, k-tree[tree[p].r].size-1);
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> minl;
char op; int k;
while (n -- ) {
cin >> op >> k;
if (op == 'I') {
if (k < minl) continue;
insert(k-delta);
} else if (op == 'A') {
delta += k;
} else if (op == 'S') {
delta -= k;
del(minl-delta);
} else {
int t = get_num(root, k);
cout << ((t == -1) ? t : t+delta) << '\n';
}
}
cout << ans << '\n';
return 0;
}
6.10:
P1110 [ZJOI2007] 报表统计:平衡树(蓝)
我们可以记录原数组第
对于插入操作 Insert i k
,那么需要在第一棵平衡树中删除
对于查找操作 MIN_GAP
,直接在第一棵平衡树中找最小值即可。对于查找操作 MIN_SORT_GAP
,直接输出
使用 fhq-treap 实现,时间复杂度
点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e6+10;
int n, m, ans = (int)1e9, a[N], b[N];
struct Node {
int l, r;
int val, key;
int size;
};
class FHQ_Treap {
private:
int root, idx;
Node tree[N];
public:
void pushup(int u) {
tree[u].size = tree[tree[u].l].size + tree[tree[u].r].size + 1;
}
int newNode(int v) {
++ idx;
tree[idx].l = tree[idx].r = 0;
tree[idx].val = v, tree[idx].key = rand();
tree[idx].size = 1;
return idx;
}
void split(int p, int v, int &x, int &y) {
if (!p) {x = y = 0; return ;}
if (tree[p].val <= v) {
x = p;
split(tree[p].r, v, tree[p].r, y);
} else {
y = p;
split(tree[p].l, v, x, tree[p].l);
}
pushup(p);
}
int merge(int x, int y) {
if (!x || !y) return x + y;
if (tree[x].key <= tree[y].key) {
tree[x].r = merge(tree[x].r, y);
pushup(x); return x;
} else {
tree[y].l = merge(x, tree[y].l);
pushup(y); return y;
}
}
void insert(int v) {
int x, y, z;
split(root, v, x, z);
y = newNode(v);
root = merge(merge(x, y), z);
}
void del(int v) {
int x, y, z;
split(root, v, x, z), split(x, v-1, x, y);
y = merge(tree[y].l, tree[y].r);
root = merge(merge(x, y), z);
}
int get_num(int p, int k) {
if (!p) return 1e9;
if (tree[tree[p].l].size >= k) return get_num(tree[p].l, k);
else if (tree[tree[p].l].size+1 == k) return tree[p].val;
else return get_num(tree[p].r, k-tree[tree[p].l].size-1);
}
int get_pre(int v) {
int x, y;
split(root, v-1, x, y);
int ans = get_num(x, tree[x].size);
root = merge(x, y);
return ans;
}
int get_suf(int v) {
int x, y;
split(root, v-1, x, y);
int ans = get_num(y, 1);
root = merge(x, y);
return ans;
}
int min_gap() {
return get_num(root, 1);
}
} Tree1, Tree2;
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
cin >> a[i]; b[i] = a[i];
if (i > 1) Tree1.insert(abs(a[i]-a[i-1]));
ans = min(ans, min(abs(a[i]-Tree2.get_pre(a[i])), abs(a[i]-Tree2.get_suf(a[i]))));
Tree2.insert(a[i]);
}
string op; int i, k;
while (m -- ) {
cin >> op;
if (op == "INSERT") {
cin >> i >> k;
if (i < n) Tree1.del(abs(a[i+1]-b[i])), Tree1.insert(abs(a[i+1]-k));
Tree1.insert(abs(k-b[i]));
b[i] = k;
ans = min(ans, min(abs(k-Tree2.get_pre(k)), abs(k-Tree2.get_suf(k))));
Tree2.insert(k);
} else if (op == "MIN_GAP") {
cout << Tree1.min_gap() << '\n';
} else {
cout << ans << '\n';
}
}
return 0;
}
P3391 【模板】文艺平衡树:* 文艺平衡树(蓝)
按大小分裂子树的 fhq-treap。
点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
int n, m;
int root, idx;
struct Node {
int l, r;
int val, key;
int size;
// 如果我们以BST的中序遍历作为答案,那么对于区间[l,r],只需交换其对应子树中所有节点的左右儿子
int tag; // 翻转懒标记
} tree[N];
void pushup(int u) {
tree[u].size = tree[tree[u].l].size + tree[tree[u].r].size + 1;
}
void pushdown(int u) { // 下传懒标记
swap(tree[u].l, tree[u].r);
tree[u].tag = 0;
tree[tree[u].l].tag ^= 1, tree[tree[u].r].tag ^= 1;
}
int newNode(int v) {
++ idx;
tree[idx].l = tree[idx].r = tree[idx].tag = 0;
tree[idx].val = v, tree[idx].key = rand();
tree[idx].size = 1;
return idx;
}
void split(int p, int k, int &x, int &y) { // 按k(子树大小)分裂
if (!p) {x = y = 0; return ;}
if (tree[p].tag) pushdown(p);
if (tree[tree[p].l].size < k) {
x = p;
split(tree[p].r, k-tree[tree[p].l].size-1, tree[p].r, y);
} else {
y = p;
split(tree[p].l, k, x, tree[p].l);
}
pushup(p);
}
int merge(int x, int y) {
if (!x || !y) return x+y;
if (tree[x].key <= tree[y].key) {
if (tree[x].tag) pushdown(x);
tree[x].r = merge(tree[x].r, y);
pushup(x); return x;
} else {
if (tree[y].tag) pushdown(y);
tree[y].l = merge(x, tree[y].l);
pushup(y); return y;
}
}
void insert(int v) {
int x, y, z;
split(root, v, x, z);
y = newNode(v);
root = merge(merge(x, y), z);
}
void reverse(int l, int r) { // 翻转区间[l,r]
int x, y, z;
split(root, r, x, z); // 分裂区间[1,r],[r+1,n]
split(x, l-1, x, y); // 分裂区间[1,l-1],[l,r]
// 注意必须先分裂r再分裂l-1
tree[y].tag ^= 1; // 打上懒标记
root = merge(merge(x, y), z);
}
void print(int u) {
if (!u) return ;
if (tree[u].tag) pushdown(u);
print(tree[u].l), printf("%d ", tree[u].val), print(tree[u].r);
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) insert(i);
int l, r;
while (m -- ) {
scanf("%d%d", &l, &r);
reverse(l, r);
}
print(root);
return 0;
}
6.11:
P2461 [SDOI2008] 递归数列:矩阵快速幂(紫)
令
令:
则有:
注意
时间复杂度
点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define int long long
const int N = 20;
int n, m, k, p, a[N][N], b[N], c[N], ans[N][N];
void mul(int a[][N], int b[][N], int c[][N]) {
int tmp[N][N]; memset(tmp, 0, sizeof tmp);
for (int i = 1; i < N; ++i) {
for (int j = 1; j < N; ++j) {
for (int k = 1; k < N; ++k)
tmp[i][j] = (tmp[i][j] + a[i][k]*b[k][j]) % p;
}
}
memcpy(c, tmp, sizeof tmp);
}
void power(int x) {
while (x) {
if (x & 1) mul(ans, a, ans);
x >>= 1;
mul(a, a, a);
}
}
int calc(int x) {
int sum = 0;
if (x <= k) {
for (int i = 1; i <= x; ++i) sum += b[i];
return sum;
}
power(x-k);
int t = ans[1][1];
memset(a, 0, sizeof a), memset(ans, 0, sizeof ans);
a[1][1] = 1, a[1][2] = 0;
for (int i = 2; i <= k+1; ++i) a[i][1] = a[i][2] = c[i-1];
for (int i = 2; i <= k; ++i) a[i][i+1] = 1;
for (int i = 2; i <= k+1; ++i) ans[1][i] = b[k-i+2], ans[1][1] += ans[1][i];
return t;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> k;
for (int i = 1; i <= k; ++i) cin >> b[i];
for (int i = 1; i <= k; ++i) cin >> c[i];
cin >> m >> n >> p;
a[1][1] = 1, a[1][2] = 0;
for (int i = 2; i <= k+1; ++i) a[i][1] = a[i][2] = c[i-1];
for (int i = 2; i <= k; ++i) a[i][i+1] = 1;
for (int i = 2; i <= k+1; ++i) ans[1][i] = b[k-i+2], ans[1][1] += ans[1][i];
cout << ((calc(n) - calc(m-1)) % p + p) % p << '\n';
return 0;
}
/*
2
1 1
1 1
2 10 1000003
*/
P1306 斐波那契公约数:* 数学,矩阵快速幂(蓝)
令
引理 1:
证明:(反证法)
若引理不成立,令
由于
引理 2:
证明:(数学归纳法)
假设
即
定理:
证明:
不妨设
根据引理 2,我们有
根据:
可以直接用矩阵快速幂来求解。
时间复杂度
点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define int long long
const int N = 5, p = 1e8;
int n, m, a[N][N], ans[N][N];
void mul(int a[][N], int b[][N], int c[][N]) {
int tmp[N][N]; memset(tmp, 0, sizeof tmp);
for (int i = 1; i < N; ++i) {
for (int j = 1; j < N; ++j)
for (int k = 1; k < N; ++k)
tmp[i][j] = (tmp[i][j] + a[i][k] * b[k][j]) % p;
}
memcpy(c, tmp, sizeof tmp);
}
void power(int x) {
ans[1][1] = ans[1][2] = 1;
while (x) {
if (x & 1) mul(ans, a, ans);
x >>= 1;
mul(a, a, a);
}
}
signed main() {
cin >> n >> m;
a[1][1] = a[1][2] = a[2][1] = 1;
power(__gcd(n, m)-2);
cout << ans[1][1] << '\n';
return 0;
}
补一道之前过了的题:
P2260 [清华集训2012]模积和:* 数论分块(紫)
不妨设
数论分块计算即可。时间复杂度
点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define int long long
#define ll __int128
const int p = 19940417;
int n, m, ans;
int calc1(int k) { // 1+2+...+k
return (ll)k * (k+1) / 2 % p;
}
int calc2(int k) { // 1^2+2^2+...+k^2
return (ll)k * (k+1) * (2*k+1) / 6 % p;
}
signed main() {
cin >> n >> m;
if (n > m) swap(n, m);
int ans1 = n*n % p;
int l = 0, r = 0;
while (l <= n) {
l = r+1;
if (n / l == 0) break;
r = min(n, n/(n/l));
ans1 = ((ans1 - (calc1(r)-calc1(l-1)+p)%p*(n/l)%p)%p + p) % p;
}
int ans2 = m*m % p;
l = 0, r = 0;
while (l <= m) {
l = r+1;
if (m / l == 0) break;
r = min(m, m/(m/l));
ans2 = ((ans2 - (calc1(r)-calc1(l-1)+p)%p*(m/l)%p)%p + p) % p;
}
int ans3 = 0;
l = 0, r = 0;
while (l <= n) {
l = r+1;
if (n / l == 0) break;
r = min(n, min(m/(m/l), n/(n/l)));
ans3 = ((ans3 + (ll)n*m%p*(r-l+1)%p - (ll)m*(calc1(r)-calc1(l-1)+p)%p*(n/l)
- (ll)n*((calc1(r)-calc1(l-1)+p)%p*(m/l)) + (ll)(calc2(r)-calc2(l-1)+p)*(m/l)*(n/l))
% p + p) % p;
}
ans = ((ll)ans1 * ans2 % p - ans3 % p + p) % p;
cout << ans << '\n';
return 0;
}
6.14:
P2195 HXY造公园:* 并查集,树的直径(紫)
需要维护节点连通性,考虑使用并查集。对于每棵树的根节点
考虑如何维护这个森林:
对于操作 1,直接输出
时间复杂度
点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
const int N = 3e5+10;
int n, m, q;
int p[N], dist[N], d[N]; // d[x]表示x所在树的直径(x为根节点)
vector<int> e[N];
int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
void merge(int u, int v, int op) {
int pu = find(u), pv = find(v);
if (pu == pv) return ;
p[pu] = p[pv];
if (op) d[pv] = max((int)(ceil(d[pu] / 2.0) + ceil(d[pv] / 2.0)) + 1, max(d[pu], d[pv]));
}
int dfs(int u, int fa) {
int ans = u;
for (auto v : e[u]) {
if (v == fa) continue;
dist[v] = dist[u] + 1;
int x = dfs(v, u);
if (dist[ans] < dist[x]) ans = x;
}
return ans;
}
int main() {
scanf("%d%d%d", &n, &m, &q);
for (int i = 1; i <= n; ++i) p[i] = i;
int u, v;
while (m -- ) {
scanf("%d%d", &u, &v);
merge(u, v, 0);
e[u].push_back(v), e[v].push_back(u);
}
for (int i = 1; i <= n; ++i) {
if (i != p[i]) continue;
dist[i] = 0; int s = dfs(i, -1);
dist[s] = 0; int t = dfs(s, -1);
d[i] = dist[t];
}
int op;
while (q -- ) {
scanf("%d", &op);
if (op == 1) scanf("%d", &u), printf("%d\n", d[find(u)]);
else scanf("%d%d", &u, &v), merge(u, v, 1);
}
return 0;
}
6.17:
P3938 斐波那契:二分,数学(绿)
可以发现,
点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <map>
#include <cmath>
#include <vector>
using namespace std;
#define int long long
const int N = 1000, M = 3e5+20;
int m;
int f[N] = {1, 1, 2};
void get(int x, vector<int> &X) {
int t = lower_bound(f+1, f+60, x) - f;
X.push_back(x);
while (x > 1 && t > 0) {
if (x-f[t] >= 1) x -= f[t], X.push_back(x);
t --;
}
sort(X.begin(), X.end());
}
signed main() {
for (int i = 3; i <= 65; ++i) f[i] = f[i-1] + f[i-2];
scanf("%lld", &m);
int x, y;
for (int i = 1; i <= m; ++i) {
scanf("%lld%lld", &x, &y);
vector<int> X, Y;
get(x, X), get(y, Y);
int l = 0, r = min(X.size(), Y.size()) - 1;
while (l < r) {
int mid = l + r + 1 >> 1;
if (X[mid] == Y[mid]) l = mid;
else r = mid-1;
}
printf("%lld\n", X[l]);
}
return 0;
}
6.19:
P4281 [AHOI2008]紧急集合 / 聚会:LCA(蓝)
先考虑
再加入第
证明:
对于一条树上路径
在 路径上: 。 不在 路径上:
在以 为根的子树中: ; 在以 为根的子树中: ; 不在 以 为根的子树中: (因为 为 路径中深度最小的节点)。
那么分别计算
时间复杂度
点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
const int N = 5e5+10;
int n, m;
int idx, dep[N], dfn[N<<1], pos[N];
int st[N<<1][20];
vector<int> e[N];
void dfs(int u, int fa) {
dfn[++ idx] = u, pos[u] = idx;
for (auto v : e[u]) {
if (v == fa) continue;
dep[v] = dep[u]+1, dfs(v, u);
dfn[++ idx] = u;
}
}
int Min(int a, int b) {
return (pos[a] < pos[b]) ? a : b;
}
void init() {
for (int i = 1; i <= idx; ++i) st[i][0] = dfn[i];
for (int i = 1; (1<<i) <= idx; ++i) {
for (int j = 1; j <= idx-(1<<i)+1; ++j)
st[j][i] = Min(st[j][i-1], st[j+(1<<i-1)][i-1]);
}
}
int query(int l, int r) {
if (l > r) swap(l, r);
int k = log2(r-l+1);
return Min(st[l][k], st[r-(1<<k)+1][k]);
}
int lca(int u, int v) {
u = pos[u], v = pos[v];
return query(u, v);
}
int dist(int u, int v) {
return dep[u] + dep[v] - 2 * dep[lca(u, v)];
}
void solve(int a, int b, int c) {
int p1 = lca(a, b), p2 = lca(a, c), p3 = lca(b, c);
int dis1 = dist(a, p1)+dist(b, p1)+dist(c, p1), dis2 = dist(a, p2)+dist(b, p2)+dist(c, p2),
dis3 = dist(a, p3)+dist(b, p3)+dist(c, p3);
int t = min(dis1, min(dis2, dis3));
if (t == dis1) printf("%d %d\n", p1, dis1);
else if (t == dis2) printf("%d %d\n", p2, dis2);
else printf("%d %d\n", p3, dis3);
}
int main() {
scanf("%d%d", &n, &m);
int u, v;
for (int i = 1; i < n; ++i) {
scanf("%d%d", &u, &v);
e[u].push_back(v), e[v].push_back(u);
}
dfs(1, -1);
init();
int a, b, c;
while (m -- ) {
scanf("%d%d%d", &a, &b, &c);
solve(a, b, c);
}
return 0;
}
P6216 回文匹配:(* 字符串究极神题)manacher,KMP,前缀和(蓝)
裸体就意味着身体。
首先对
对于
(其中
注意到
时间复杂度
点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 3e6+10;
int n, m, ne[N], d[N];
unsigned int a[N], s1[N], s2[N];
unsigned int ans;
char S[N], T[N];
void get_next() {
ne[1] = 0;
for (int i = 2, j = 0; i <= m; ++i) {
while (T[i] != T[j+1] && j) j = ne[j];
if (T[i] == T[j+1]) j ++;
ne[i] = j;
}
}
void get_d() {
d[1] = 1;
for (int i = 2, l = 0, r = 0; i <= n; ++i) {
int j = l + r - i;
if (i <= r) d[i] = min(d[j], r-i+1);
while (S[i+d[i]] == S[i-d[i]] && i-d[i] >= 1 && i+d[i] <= n) d[i] ++;
if (i+d[i] > r) r = i+d[i]-1, l = i-d[i]+1;
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m >> S+1 >> T+1;
get_next();
for (int i = 1, j = 0; i <= n; ++i) {
while (S[i] != T[j+1] && j) j = ne[j];
if (S[i] == T[j+1]) j ++;
if (j == m) a[i-m+1] ++, j = ne[j];
}
for (int i = 1; i <= n; ++i) s1[i] = s1[i-1]+a[i], s2[i] = s2[i-1]+i*a[i];
get_d();
for (int i = 1; i <= n; ++i) {
int l = i-d[i]+1, r = i+d[i]-m, mid = l + r >> 1;
if (l > r) continue;
ans += -(unsigned int)(l-1)*(s1[mid]-s1[l-1]) + s2[mid]-s2[l-1];
if (r != mid) ans += (unsigned int)(r+1)*(s1[r]-s1[mid]) - s2[r]+s2[mid];
}
cout << ans << '\n';
return 0;
}
Codeforces Round 878 (Div. 3):
CF1840B:
CF1840C:预处理 vector
中。正序扫描
CF1840D:二分答案即可。
点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 2e5+10;
int t, n, a[N];
bool check(int num) {
int x = 1, cnt = 0;
// printf("%d\n", num);
while (x <= n && cnt < 3) {
// printf("%d ", x);
x = upper_bound(a+1, a+n+2, a[x]+2*num) - a, cnt ++;
}
// printf("%d\n", x);
if (x > n) return 1;
return 0;
}
int main() {
scanf("%d", &t);
while (t -- ) {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
a[n+1] = 1000000000;
sort(a+1, a+n+2);
int l = 0, r = 1000000000;
while (l < r) {
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid+1;
}
printf("%d\n", l);
}
return 0;
}
CF1840E:用一个变量
点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
typedef pair<int, int> pii;
const int N = 2e5+10;
int T, t, q, n, c[N];
string s1, s2;
char s[3][N];
int id; vector<pii> oper;
int lowbit(int x) {
return x & -x;
}
void add(int x, int k) {
for (int i = x; i <= n; i += lowbit(i))
c[i] += k;
}
int query(int x) {
int sum = 0;
for (int i = x; i > 0; i -= lowbit(i))
sum += c[i];
return sum;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> T;
while (T -- ) {
id = 0, oper.clear(); memset(c, 0, sizeof c);
cin >> s1 >> s2 >> t >> q;
n = s1.size();
for (int i = 1; i <= n; ++i) s[0][i] = s1[i-1], s[1][i] = s2[i-1];
for (int i = 1; i <= n; ++i) {
if (s[0][i] != s[1][i])
add(i, 1);
}
int op, x, y, pos1, pos2;
for (int i = 1; i <= q; ++i) {
if (id < oper.size() && i == oper[id].first) {
add(oper[id].second, 1);
id ++;
}
cin >> op;
if (op == 1) {
cin >> pos1;
if (s[0][pos1] != s[1][pos1]) add(pos1, -1), oper.push_back({i+t, pos1});
} else if (op == 2) {
cin >> x >> pos1 >> y >> pos2; x --, y --;
if (s[x][pos1] != s[x^1][pos1]) add(pos1, -1);
if (s[y][pos2] != s[y^1][pos2]) add(pos2, -1);
swap(s[x][pos1], s[y][pos2]);
if (s[x][pos1] != s[x^1][pos1]) add(pos1, 1);
if (s[y][pos2] != s[y^1][pos2]) add(pos2, 1);
} else if (op == 3) {
if (!query(n)) cout << "YES\n";
else cout << "NO\n";
}
// for (int i = 1; i <= n; ++i) {
//// if (query(i)-query(i-1) == 0)
// cout << s[0][i];
// }
// cout << '\n';
// for (int i = 1; i <= n; ++i) {
//// if (query(i)-query(i-1) == 0)
// cout << s[1][i];
// }
// cout << '\n';
// for (int i = 1; i <= n; ++i) cout << query(i) - query(i-1) << ' ';
// cout << '\n';
}
}
return 0;
}
本文作者:Jasper08
本文链接:https://www.cnblogs.com/Jasper08/p/17529926.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具