0%

题目大意

题目描述
构造一个长度不超过 500500 且仅由大写字母 CGAT 组成的非空字符串,使其满足以下两个条件:

  1. 字符串中包含恰好 GG 个子序列 GATA(即字符 GATA 按顺序出现,中间可以包含其他字符)。

  2. 字符串中包含恰好 CC 个子序列 CAT(即字符 CAT 按顺序出现,中间可以包含其他字符)。

输入格式
第一行包含一个整数 QQ1Q10001 \le Q \le 1000),表示询问的组数。
接下来的 QQ 行,每行包含两个整数 GGCC0G,C1060 \le G, C \le 10^6),分别表示所需的 GATA 子序列的数量和 CAT 子序列的数量。

输出格式
对于每组询问,输出一行满足条件的字符串(长度不超过 500500 且仅包含 CGAT)。如果存在多个解,输出任意一个即可。题目保证在给定限制下一定有解。

样例输入与输出

样例 1:

1
2
3
4
5
6
7
8
9
10
11
12
Input:
4
1 1
2 3
18 1
2 1

Output:
GATCAT
GGCATAT
GATGGATATCAT
GGATCAT

样例 2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Input:
5
1 0
0 1
1 1
0 0
0 0

Output:
GATAT
CAT
GATCAT
GG
GG

样例解释

对于样例 1 的第一组询问(G=1,C=1G=1, C=1),输出为 GATCAT

  • GATA 子序列的数量为 11(由第 1 个字符 G、第 2 个字符 A、第 3 个字符 T、第 5 个字符 A 组成)。

  • CAT 子序列的数量为 11(由第 4 个字符 C、第 5 个字符 A、第 6 个字符 T 组成)。

对于样例 2 的第一组询问(G=1,C=0G=1, C=0),输出为 GATAT

  • GATA 子序列的数量为 11(由第 1 个字符 G、第 2 个字符 A、第 3 个字符 T、第 5 个字符 A 组成)。

  • 由于字符串中完全不包含字符 C,因此 CAT 子序列的数量为 00

思路讲解

image

AC代码

心路历程(WA,TLE,MLE……)

题目大意

image

一开始没注意到这句话,绷不住了。注意,读题面,一定要把每句话都读到,你就看大写字母就完了

也不能怪我,这个 if 在 cf 题面上的这个位置太阴了。

image

题意总结

给定 NN 个球,以及它们被依次使用时的颜色序列 K1,K2,,KNK_1,K_2,\dots,K_N

Antonella 按如下规则逐个放球,且每一步之后都必须保持整个球堆稳定:

image

  1. 第一个球一定放在地面上。

  2. 之后每次加入一个新球时,这个球要么放在地面上,要么恰好放在两个球的正上方。

  3. 所有在地面上的球必须紧密排列,中间不能有空隙。

  4. 如果当前有多个合法放置位置,Antonella 一定选择最高的位置。

  5. 如果最高的位置不止一个,则她可以任选其中一个。

若若干个同色球两两之间可以通过“接触”的球一路连通,则它们构成一个同色连通块,称为一个 cluster。cluster 的大小就是其中球的个数。

题目要求你在所有可能构造出的稳定球堆中,求出:

所有颜色的所有 cluster 里,最大 cluster 的大小 的最大可能值。

也就是说,要输出 Antonella 在满足规则的前提下,最终有可能得到的最大同色连通块大小。

输入格式

第一行是整数 NN

第二行是 NN 个整数 K1,K2,,KNK_1,K_2,\dots,K_N,表示每个球按加入顺序的颜色。

输出格式

输出一个整数,表示答案。

样例 1

1
2
3
4
5
6
Input
3
1 2 1

Output
2

解释:

先放第一个颜色为 1 的球。第二个颜色为 2 的球也只能放在地面上,可以放在第一个球左边或右边。第三个颜色为 1 的球此时会放到前两个球上方。这样最终颜色为 1 的两个球会连成一个大小为 2 的 cluster,所以答案是 2

样例 2

1
2
3
4
5
6
Input
3
1 1 1

Output
3

解释:

三个球颜色都相同,不管具体怎么放,最终都能连成一个大小为 3 的同色 cluster,所以答案是 3

样例 3

1
2
3
4
5
6
Input
4
1 5 5 1

Output
2

解释:

按规则逐步加入后,最大的同色连通块大小最多只能达到 2,因此答案是 2

样例 4

1
2
3
4
5
6
Input
6
1 2 2 1 2 3

Output
3

解释:

在某种合法构造下,颜色为 2 的球可以形成一个大小为 3 的 cluster,因此答案是 3

思路讲解

这道题目不是很想补,毕竟暴力嘛,算了。

AC代码

心路历程(WA,TLE,MLE……)

题目大意

题目描述
在一个圆上有 NN 只蚂蚁。圆被顺时针划分为 LL 个位置,编号为 11LL,其中位置 LL 与位置 11 相邻。
每只蚂蚁初始站在不同的位置上,并且都需要到达各自不同的目标位置。
在每一秒内,每只蚂蚁可以选择:

  • 停留在原地。

  • 顺时针或逆时针移动到相邻的位置。

在任何时刻(包括在两个位置之间移动的过程中),任意两只蚂蚁都不能处于同一个位置。例如,如果某只蚂蚁在某一秒内顺时针从位置 11 移动到位置 22,那么在同一秒内,其他蚂蚁不能进行以下操作:

  • 停留在位置 22(这会导致两只蚂蚁在位置 22 相遇)。

  • 逆时针从位置 33 移动到位置 22(这会导致两只蚂蚁在位置 22 相遇)。

  • 逆时针从位置 22 移动到位置 11(这会导致两只蚂蚁在位置 11 和位置 22 之间相遇)。

你需要判断是否有可能让所有蚂蚁都到达各自的目标位置。如果可以,求出所需的最短时间(秒数)。

输入格式
第一行包含两个整数 NN1N10001 \le N \le 1000)和 LL1L1091 \le L \le 10^9),分别表示蚂蚁的数量和位置的总数。
第二行包含 NN 个互不相同的整数 A1,A2,,ANA_1, A_2, \dots, A_N1AiL1 \le A_i \le L),表示每只蚂蚁的初始位置。
第三行包含 NN 个互不相同的整数 B1,B2,,BNB_1, B_2, \dots, B_N1BiL1 \le B_i \le L),表示每只蚂蚁的目标位置。

输出格式
输出一行,包含一个整数,表示所有蚂蚁到达目标位置所需的最短时间。如果无论如何都无法全部到达目标位置,则输出星号 *

样例展示与解释

样例 1
输入:

1
2
3
2 2
2 1
2 1

输出:

1
0

样例 1 解释:两只蚂蚁初始就已经在各自的目标位置上,因此需要 00 秒。

样例 2
输入:

1
2
3
2 2
1 2
2 1

输出:

1
1

样例 2 解释:两只蚂蚁可以同时顺时针(或同时逆时针)移动,仅需 11 秒即可到达目标位置。

样例 3
输入:

1
2
3
1 10
1
7

输出:

1
4

样例 4
输入:

1
2
3
3 5
1 3 2
5 2 4

输出:

1
*

样例 5
输入:

1
2
3
3 5
1 3 2
4 2 5

输出:

1
2

样例 5 解释:三只蚂蚁都可以选择逆时针移动,其中第二只蚂蚁需要在中途停留一秒。

思路讲解

image

这道题目,实际上可以 O(n)O(n) 解决(忽略了快排的时间复杂度),至少我们的做法是这个时间复杂度的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
sort(all(lr_global));
for (int i = 0; i < SZ(lr_global); ++i) {
if (lr_global[0].r > lr_global[i].r) {
lr_global[i].r += L;
}
}
auto check = [&]() -> bool {
for (int i = 1; i < N; ++i) {
if (lr_global[i].l == lr_global[i - 1].l) {
return false;
}
}
for (int i = 1; i < N; ++i) {
if (lr_global[i].r <= lr_global[i - 1].r) {
return false;
}
}
return true;
};
if (!check()) {
cout << "*\n";
return;
}

核心代码就这一段,只能说化曲为直 yyds。

1
2
3
4
5
6
7
for (ll shift: {-1, 0, 1}) {
ll ans = 0;
for (auto [l,r]: lr_global) {
ans = max(abs(l + L * shift - r), ans);
}
ans_global = min(ans_global, ans);
}

为什么这个代码对呢?其实在化曲为直下,一切都非常简单。

说白了,我们只要 l 的相对位置不变,r 的相对位置不变,那么就一定有解,是不是?

那么,我们知道,一个点,他切换方向,其实就是 l 在化曲为直的线段上,平移了 Len 位如果其他点不也平移的 L 位的话,这个一定会导致错误的发生(即 l 的相对位置发生变化)!

那么我们就知道了,要切换方向,要么一起切换,要么一起不切换

当然,你会说,这很奇怪啊,明明这个有些例子是有些点逆时针,有些点顺时针啊?其实,这个是因为为了符合我们的第一个条件,就是起始点和结束点必须都保持升序的条件,在保持这个条件的情况下,其实方向的变化是一起的。

AC代码

AC
http://codeforces.com/gym/106416/submission/368041079

心路历程(WA,TLE,MLE……)

题目大意

题目描述
维护一个初始为空的多重集。每次从中取出一个元素时,集合中每个元素被取出的概率均等,取出后该元素从集合中删除。每次取出事件相互独立。
给定 nn 次操作序列,操作分为两种:

  1. 向集合中插入一个给定的非负整数。

  2. 从集合中随机取出一个元素。
    保证每次取出时集合非空,且整个操作序列至少包含一次取出操作。
    求所有被取出的元素排成的序列满足单调不降(即序列中每一项都小于等于它的后一项)的概率。答案对 998244353 取模。

输入格式
第一行包含一个正整数 TT1T2.5×1031 \le T \le 2.5 \times 10^3),表示测试数据组数。
每组数据第一行包含一个整数 nn2n5×1032 \le n \le 5 \times 10^3),表示操作总数。
第二行包含 nn 个整数 a1,a2,,ana_1, a_2, \dots, a_n1ain-1 \le a_i \le n),表示操作序列:

  • ai0a_i \ge 0 表示向集合中插入 aia_i

  • ai=1a_i = -1 表示从集合中随机取出一个元素。
    保证所有数据的 n5×103\sum n \le 5 \times 10^3

输出格式
对于每组数据,输出一行一个整数,表示概率对 998244353 取模的结果。

样例输入 1

1
2
3
4
5
6
7
3
3
1 2 -1
5
1 2 -1 3 -1
7
1 2 3 4 -1 -1 -1

样例输出 1

1
2
3
1
249561089
166374059

样例输入 2

1
2
3
4
5
6
7
3
4
1 2 -1 -1
6
1 2 -1 -1 1 -1
8
1 -1 2 -1 3 -1 4 -1

样例输出 2

1
2
3
499122177
0
1

样例解释
对于样例一的第 1 组数据,由于总共只取出了一个元素,序列无论如何都是单调不降的,概率为 1。

对于样例一的第 2 组数据,操作过程和对应概率如下:

  • 加入 1,集合变为 {1}\{1\};加入 2,集合变为 {1,2}\{1, 2\}

  • 此时取出 1 的概率为 12\frac{1}{2}。若取出 1,接下来加入 3,集合变为 {2,3}\{2, 3\}。之后无论取出哪个数,得到的序列(1 然后是 2 或 1 然后是 3)均满足单调不降。此情况的合法概率为 12×1=12\frac{1}{2} \times 1 = \frac{1}{2}

  • 此时取出 2 的概率为 12\frac{1}{2}。若取出 2,接下来加入 3,集合变为 {1,3}\{1, 3\}。之后为了保持单调不降,必须取出 3,取出 3 的概率为 12\frac{1}{2}。此情况的合法概率为 12×12=14\frac{1}{2} \times \frac{1}{2} = \frac{1}{4}
    最终单调不降的总概率为 12+14=34\frac{1}{2} + \frac{1}{4} = \frac{3}{4}34\frac{3}{4} 对 998244353 取模的结果为 249561089。

思路讲解

image

这道题目其实不难,就是细节比较多。

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
for (ll op = 1; op <= cnt_op; ++op) {
vector<ll> vals;
for (int val = 0; val <= N; ++val) {
if (op_val_cnt[op][val] >= 1) {
vals.push_back(val);
}
}
if (op == 1) {
for (auto val: vals) {
dp_val_cnt[val].resize(2);
// 注意,有多个数字可选的时候,有多种可能,答案不是 1
dp_val_cnt[val][1] = op_val_cnt[op][val];
dpacc_val[val] = op_val_cnt[op][val];
}
} else {
vector<vector<ll> > ndp_val_cnt(N + 2);
vector<ll> ndpacc_val(N + 2);
vector<ll> presum_dpacc(N + 2);
// 注意使用前缀和优化
partial_sum(all(dpacc_val), presum_dpacc.begin(), [](ll a, ll b) {
return (a + b) % mod;
});
for (auto val: vals) {
ll val_cnt = op_val_cnt[op][val];
ndp_val_cnt[val].resize(min(op, val_cnt) + 2);
for (int cnt = 1; cnt <= min(op, val_cnt); ++cnt) {
ll rem_val = val_cnt - cnt + 1;
if (cnt >= 2) {
if (cnt - 1 > SZ(dp_val_cnt[val]) - 1) {
break;
}
ndp_val_cnt[val][cnt] = rem_val * dp_val_cnt[val][cnt - 1];
ndp_val_cnt[val][cnt] %= mod;
} else {
// for (int s_val = 0; s_val < val; ++s_val) {
// ndp_val_cnt[val][cnt] += dpacc_val[s_val];
// ndp_val_cnt[val][cnt] %= mod;
// }
if (val - 1 >= 0) {
ndp_val_cnt[val][cnt] = presum_dpacc[val - 1];
}
ndp_val_cnt[val][cnt] *= rem_val;
ndp_val_cnt[val][cnt] %= mod;
}
ndpacc_val[val] += ndp_val_cnt[val][cnt];
ndpacc_val[val] %= mod;
}
}
swap(dp_val_cnt, ndp_val_cnt);
swap(dpacc_val, ndpacc_val);
}
}

AC代码

AC
https://codeforces.com/gym/105941/submission/367931586

心路历程(WA,TLE,MLE……)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
do {
// 注意,还是要把 numc 显式地写出来
ll opc = 0, numc = 0;
vector<ll> cnt(N + 2);
for (int i = 1; i <= N; ++i) {
if (A[i] == -1) {
tot_num *= (numc - opc);
tot_num %= mod;
opc++;
op_val_cnt[opc] = cnt;
} else {
cnt[A[i]]++;
numc++;
}
}
} while (false);

2025 National Invitational of CCPC (Zhengzhou), 2025 CCPC Henan Provincial Collegiate Programming Contest

题目大意

给定一个长度为 nn 的数组 aa,初始时第 ii 个位置的值为 aia_i1ain1 \le a_i \le n)。共有 mm 次操作,每次操作给定 l,r,dl, r, d,将区间 [l,r][l, r] 内的值依次替换为 d,d+1,,d+rld, d+1, \ldots, d+r-l

在初始状态以及每次操作后,输出数组中出现次数最多的值及其出现次数。若有多个值出现次数相同,输出其中编号最小的。

多组测试数据,TT 组,保证 n2×105\sum n \le 2 \times 10^5m2×105\sum m \le 2 \times 10^5

样例

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
输入:
3
3 3
1 2 3
1 1 2
2 2 3
3 3 1
1 1
1
1 1 1
8 8
7 6 6 4 3 8 5 3
4 4 4
6 8 6
1 1 7
4 7 4
6 7 6
2 7 5
1 5 7
1 6 8

输出:
1 1
2 2
3 2
1 1
1 1
1 1
3 2
3 2
6 3
6 3
6 3
6 3
7 2
8 2
8 2

样例解释(第一组数据)

初始数组为 [1,2,3][1, 2, 3],三个值各出现 11 次,输出最小编号 11,次数 11

11 次操作 l=1,r=1,d=2l=1, r=1, d=2:将位置 11 替换为 22,数组变为 [2,2,3][2, 2, 3],值 22 出现 22 次最多,输出 2 22\ 2

22 次操作 l=2,r=2,d=3l=2, r=2, d=3:将位置 22 替换为 33,数组变为 [2,3,3][2, 3, 3],值 33 出现 22 次最多,输出 3 23\ 2

33 次操作 l=3,r=3,d=1l=3, r=3, d=1:将位置 33 替换为 11,数组变为 [2,3,1][2, 3, 1],三个值各出现 11 次,输出最小编号 11,次数 11

思路讲解

我看了一下,宝可梦这道题目珂朵莉树不会被卡的原因是因为全局查询,可以通过维护全局信息解决这个问题。
好像只要改成区间查询,区间修改,珂朵莉树一定会被卡

珂朵莉树的时间复杂度过于玄学了,我还是想用这个时间复杂度更加确定的算法解决问题。

还是学一下珂朵莉树吧,好像这道题目只能用珂朵莉树,或者至少用珂朵莉树最简单,其他各种各样,形形色色的数据结构,都不是说特别好。

image

不难发现,珂朵莉树只有 assign 操作,肯定是 O(nlogn)O(n\log n),当然,这个东西没有那么显然,但是不难理解。因为 l,r 越大,需要遍历的区间就越多,但是一次性也把很多区间给整合在一起了。区间小嘛,一共就不遍历几个区间,何谈什么复杂度?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template<class F>
void assign(ll l, ll r, ll val, F on_change) {
// 这个顺序对于我们 mp 珂朵莉树实现无所谓
split(r + 1);
split(l);
auto it = mp.lower_bound(l);
while (it != mp.end() && it->first <= r) {
ll st=it->first;
auto [ed,val]=it->second;
// 具体怎么调用看你的 on_change() 实现,一般是一个全局操作
on_change();
it = mp.erase(it);
}
mp[l]={r,val};
on_change();
}

我感觉那种只问一次,或者像这种全局询问的,都非常适合珂朵莉树

AC代码

AC
https://codeforces.com/gym/105941/submission/368114371

starsilk 的代码

https://codeforces.com/gym/105941/submission/322881549

心路历程(WA,TLE,MLE……)