发布于  更新于 

2024 ICPC 成都I

原题链接

题意

给定一个长度为 的序列 ,问有多少个好的划分。

一个大小为 的好的划分定义为将 划分为 个部分(最后一部分可能少于 个数),每个部分内部都单调不降。

现在有 次修改,每次修改将 修改为 ,计算修改前和每次修改后好的分区的数量。

题解

首先一个容易得到的性质是,如果一个数 满足条件,则 的所有因数均满足条件。

同时两个数 满足条件,则 也满足条件。

这提示我们去找一个最大的 ,然后所有满足条件数的集合即为

由于每一段内部都要单调不降,则每一个 的地方一定是一个分界点,找出所有这样的位置,然后它们的最大公因数就是最大的满足条件的

用线段树维护区间gcd即可。

时间复杂度

代码

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
#include <bits/stdc++.h>
#define endl "\n"
using namespace std;
constexpr int N = 2e5 + 10;
int aa[N];
struct node {
int l, r, v;
} tr[N << 2];

void pushup(int u) { tr[u].v = __gcd(tr[u << 1].v, tr[u << 1 | 1].v); }

void build(int u, int l, int r)
{
if (l == r) {
tr[u] = {l, r, aa[l]};
return;
}
int mid = l + r >> 1;
tr[u] = {l, r, 0};
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
pushup(u);
}

void modify(int u, int l, int r, int v)
{
if (tr[u].l >= l && tr[u].r <= r) {
tr[u].v = v;
return;
}
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) modify(u << 1, l, r, v);
if (mid < r) modify(u << 1 | 1, l, r, v);
pushup(u);
}

void solve()
{
int n, q;
cin >> n >> q;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
vector<int> b(n + 1);
for (int i = 1; i < n; i++) {
aa[i] = a[i] > a[i + 1] ? i : 0;
}

vector<int> d(n + 1);
for (int i = 1; i <= n; i++) {
for (int j = i; j <= n; j += i) {
d[j]++;
}
}
d[0] = n;

build(1, 1, n);
cout << d[tr[1].v] << endl;
while (q--) {
int p, v;
cin >> p >> v;
if (p - 1 >= 1) {
if (a[p - 1] <= a[p] && a[p - 1] > v) {
modify(1, p - 1, p - 1, p - 1);
}
else if (a[p - 1] > a[p] && a[p - 1] <= v) {
modify(1, p - 1, p - 1, 0);
}
}
if (p + 1 <= n) {
if (a[p] <= a[p + 1] && v > a[p + 1]) {
modify(1, p, p, p);
}
else if (a[p] > a[p + 1] && v <= a[p + 1]) {
modify(1, p, p, 0);
}
}
a[p] = v;
cout << d[tr[1].v] << endl;
}
}

int main()
{
ios::sync_with_stdio(false), cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}

本站由 @zhengzx 使用 Stellar 主题创建。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。