0%

题目大意

题意总结

给定长度为 N 的字符串 S,字符只可能是 01?

把所有 ? 分别替换成 01 后,会得到一个二进制串。

定义“好串”为:所有 1 必须恰好出现在一个连续子串中(可以没有 1,也可以全是 1)。

对一个确定的二进制串,定义 f(S) 为把它变成“好串”的最少操作次数。

一次操作是:选 1 ≤ i < j ≤ N,交换 S[i]S[j]

每个测试用例要求输出两件事:

  • 在所有可能替换方案里,f(S) 的最小可能值

  • 在所有可能替换方案里,f(S) 的最大可能值


输入格式

  • 第一行:整数 T,表示测试用例数。

  • 每个测试用例两行:

    • 第一行:整数 N
    • 第二行:长度为 N 的字符串 S

输出格式

每个测试用例输出一行两个整数:min_f max_f,分别表示最小和最大可能的 f(S)


数据范围

  • 1 ≤ T ≤ 100

  • 2 ≤ N ≤ 2000

  • S[i] ∈ {0,1,?}

  • 所有测试用例的 N 之和不超过 2000


样例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Input
6
3
1?1
5
1?0?1
7
1?0101?
9
?????????
8
11010101
6
??011?

Output
0 1
1 1
1 2
0 3
2 2
0 1

样例说明(按测试点)

  • 第 1 组:1?1

    • 最小值:取 111,已经是好串,f=0
    • 最大值:取 101,最少交换 1 次变好串,f=1
    • 所以输出 0 1
  • 第 2 组:1?0?1

    • 无论怎么填,f 的最小和最大都为 1
    • 输出 1 1
  • 第 3 组:1?0101?

    • 可构造到 f=1(如 1101010
    • 也可构造到 f=2(如 1101011
    • 输出 1 2
  • 第 4 组:?????????

    • 最小可到 0(如全 0 或全 1
    • 最大可到 3(如 111000111
    • 输出 0 3
  • 第 5 组:11010101

    • 没有 ?,串固定,f 唯一为 2
    • 输出 2 2
  • 第 6 组:??011?

    • 最小可到 0
    • 最大可到 1
    • 输出 0 1

思路讲解

AC代码

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

题目大意

  • 给定长度为 NN 的数组 AA

  • 好数组(good) 的定义:数组中存在至少一个数值 xx,它在该数组中恰好出现一次

    • 例如 [1,2,1][1,1,2] 是好数组(2 只出现一次)。
    • [1,2,1,2] 不是好数组(每个值都出现两次)。
  • 漂亮数组(beautiful) 的定义:这个数组的每一个子数组(连续子段)都是好数组。

    • 例如 [1,2,1] 是漂亮数组;[1,1,2][1,2,1,2] 不是。
  • 你可以进行若干次修改操作:每次选择位置 ii,把 AiA_i 改成任意整数 xx

  • 目标:对每个测试用例,求把原数组变成漂亮数组所需的最少修改次数

  • 输入格式:

    • 第一行是测试组数 TT
    • 每组先给 NN,再给 NN 个整数 A1,,ANA_1,\dots,A_N
  • 输出格式:

    • 每组输出一个整数,表示最少修改次数。
  • 数据范围:

    • 1T1031 \le T \le 10^3
    • 2N5002 \le N \le 500
    • 1AiN1 \le A_i \le N
    • 所有测试用例的 N2N^2 之和不超过 5002500^2

样例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
输入
4
3
1 3 1
3
1 1 2
4
1 2 1 2
6
1 1 1 2 1 2

输出
0
1
1
2
  • 样例第 1 组:[1,3,1] 本身已经是漂亮数组,所以答案是 0

  • 样例第 2 组:[1,1,2] 不是漂亮数组,改一次即可(如把第 2 个数改成 3,得到 [1,3,2]),答案是 1

  • 样例第 3 组:[1,2,1,2] 不是漂亮数组,最少改 1 次。

  • 样例第 4 组:[1,1,1,2,1,2] 最少改 2 次。

思路讲解

PDF

AC代码

AC
https://www.codechef.com/viewsolution/1263070965

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

题目大意

题目描述
给定两个长度为 nn 的整数数组 aabb
qq 次询问,每次询问给定一个区间 [l,r][l, r],提取出子数组 a=a[lr]a' = a[l \dots r]b=b[lr]b' = b[l \dots r],设该子数组长度为 m=rl+1m = r - l + 1
对于每次询问中的子数组,可以执行以下操作任意次:

  1. 选取一个下标 ii1im1 \le i \le m)。

  2. 计算子数组后缀的最大公约数 gi=gcd(ai,ai+1,,am)g_i = \gcd(a'i, a'{i+1}, \dots, a'_m)

  3. bb' 中下标从 iimm 的所有元素减去 gig_i(即对于所有 ijmi \le j \le m,令 bjbjgib'_j \leftarrow b'_j - g_i)。

每次操作的代价为 1。要求计算出使 bb' 中所有元素变为非正数(0\le 0)所需的最小总操作代价。

数据范围

  • 测试组数 TT1T1051 \le T \le 10^5

  • 数组长度与询问次数 n,qn, q1n,q21051 \le n, q \le 2 \cdot 10^5

  • 数组元素范围:1ai1091 \le a_i \le 10^90bi1090 \le b_i \le 10^9

  • 保证 n106\sum n \le 10^6q106\sum q \le 10^6

样例数据

输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
10 10
6 12 18 40 50 60 105 120 135 150
10 20 30 40 50 60 70 80 90 100
5 8
1 3
7 10
6 6
4 7
1 6
2 10
2 4
4 4
5 6

输出

1
2
3
4
5
6
7
8
9
10
12
5
7
1
12
18
38
16
1
6

样例解释
以第 2 次询问 1 3 为例:
提取出的子数组为 a=[6,12,18]a' = [6, 12, 18]b=[10,20,30]b' = [10, 20, 30]
一种可能的最优操作序列如下(共需 5 次操作,代价为 5):

  • 选取 i=1i = 1 操作 2 次:g1=gcd(6,12,18)=6g_1 = \gcd(6, 12, 18) = 6,每次操作使 b1,b2,b3b'_1, b'_2, b'_3 减去 6。操作后 bb' 变为 [2,8,18][-2, 8, 18]

  • 选取 i=2i = 2 操作 2 次:g2=gcd(12,18)=6g_2 = \gcd(12, 18) = 6,每次操作使 b2,b3b'_2, b'_3 减去 6。操作后 bb' 变为 [2,4,6][-2, -4, 6]

  • 选取 i=3i = 3 操作 1 次:g3=gcd(18)=18g_3 = \gcd(18) = 18,每次操作使 b3b'_3 减去 18。操作后 bb' 变为 [2,4,12][-2, -4, -12]
    此时 bb' 中所有元素均不大于 0,所需最小总代价为 2+2+1=52 + 2 + 1 = 5,与输出一致。

思路讲解

PDF

想出一个 O(nq)O(nq) 的做法是不难的,难的就是怎么样在 O(n+q)O(n+q) 或者类似的时间复杂度内解决这个问题。

这个下面就是一个这样的做法:

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
struct Solve {
ll N, Q;
vector<ll> A_glo;
vector<ll> B_glo;
vector<ll> gcd_ls;

ll reply_to_query(ll l, ll r) {
gcd_ls[r] = A_glo[r];
for (int i = r - 1; i >= l; --i) {
gcd_ls[i] = __gcd(gcd_ls[i + 1], A_glo[i]);
}
ll acc = 0;
ll ans = 0;
for (int i = l; i <= r; ++i) {
if (acc >= B_glo[i]) {
continue;
}
ll rem = B_glo[i] - acc;
ll add = (rem + gcd_ls[i] - 1) / gcd_ls[i];
acc += add * gcd_ls[i];
ans += add;
}
return ans;
}

Solve() {
cin >> N >> Q;
A_glo.resize(N + 2);
B_glo.resize(N + 2);
gcd_ls.resize(N + 2);
for (int i = 1; i <= N; ++i) {
cin >> A_glo[i];
}
for (int i = 1; i <= N; ++i) {
cin >> B_glo[i];
}
for (int _ = 1; _ <= Q; _++) {
ll l, r;
cin >> l >> r;
cout << reply_to_query(l, r) << "\n";
}
}
};

image

image

AC代码

AC
https://acm.hdu.edu.cn/contest/view-code?cid=1200&rid=15202

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

题目大意

题目大意

给定一个 n×nn \times n 的方阵 aa,其外围被一圈值为 1010010^{100} 的元素包围,共同形成一个 (n+2)×(n+2)(n+2) \times (n+2) 的方阵。
每个元素代表一个人的识别码。对于给定的通行证 cardcard,如果一个人的识别码 xx 满足 xx 按位或 cardcardcard \neq card(即 xx 的二进制表示中存在 cardcard 没有的 11),则该人被视为“坏蛋”。(由于外围一圈元素的值极大,它们一定会满足该条件被判定为坏蛋)。

每个人(包含坏蛋自身)的安全感定义为:从当前位置出发,沿上下左右四个直线方向寻找,距离其最近的坏蛋的距离。如果自身是坏蛋,则距离为 00

现在有 qq 次询问,每次给定一个 cardcard,求方阵 aa 中所有人的安全感之和。

数据范围

  • 1T101 \le T \le 10

  • 1n3001 \le n \le 300

  • 1q5×1041 \le q \le 5 \times 10^4

  • 0ai,j<2150 \le a_{i,j} < 2^{15}

  • 0card<1090 \le card < 10^9

样例输入

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

样例输出

1
12

样例解释

在样例中,n=5n=5card=1card = 1
由于坏蛋的条件是 xx 按位或 111 \neq 1,因此识别码为 11 的是好人(用 G 表示),识别码为 55 的是坏蛋(用 B 表示)。外围一圈全部是极大值,均为 B。方阵的状态如下:

1
2
3
4
5
6
7
B B B B B B B
B B B G B B B
B B B G B B B
B G G G G G B
B B B G B B B
B G B G B B B
B B B B B B B

我们可以计算每个好人位置上,在上下左右四个直线方向中,遇到最近的坏蛋的距离:

  • 对于 (1,3)(1, 3)G,向上一步即为外围的 B,距离为 11

  • 对于 (2,3)(2, 3)G,向左一步为内部的 B,距离为 11

  • 对于第三行的四个 G(除了中心 (3,3)(3, 3)):

    • (3,1)(3, 1) 向上一步为 B,距离为 11
    • (3,2)(3, 2) 向上一步为 B,距离为 11
    • (3,4)(3, 4) 向上一步为 B,距离为 11
    • (3,5)(3, 5) 向上一步为 B,距离为 11
  • 对于中心的 (3,3)(3, 3),它的上下左右连续两个位置都是 G,直到第三个位置才是外围或内部的 B,因此最近距离为 33

  • 对于 (4,3)(4, 3)G,向左一步为内部的 B,距离为 11

  • 对于第五行的两个 G

    • (5,1)(5, 1) 向右一步为内部的 B,距离为 11
    • (5,3)(5, 3) 向左一步为内部的 B,距离为 11

将所有好人的距离相加:1+1+1×4+3+1+1×2=121 + 1 + 1 \times 4 + 3 + 1 + 1 \times 2 = 12。坏蛋自身的最近距离为 00,因此安全感总和为 1212,与样例输出一致。

思路讲解

AC代码

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

题目大意

题目描述
给定 nn 辆列车的停放区间 [l,r][l, r]
mm 次询问,每次询问给出一个空区间 [x,y][x, y],需要求出在该空区间内最多可以完整停放多少辆列车。
被选择停放的列车区间必须完全包含在询问区间 [x,y][x, y] 内,且不同列车的停放区间在内部不能重叠,但端点可以相交(即列车之间可以紧贴,不留空隙)。

输入格式
第一行输入一个整数 TT1T51 \le T \le 5),表示测试数据组数。
对于每组数据:
第一行输入一个整数 nn1n1051 \le n \le 10^5),表示列车数量。
接下来 nn 行,每行输入两个整数 l,rl, r1l<r1091 \le l < r \le 10^9),表示一辆列车的停放区间为 [l,r][l, r]
接下来一行输入一个整数 mm1m1051 \le m \le 10^5),表示询问次数。
接下来 mm 行,每行输入两个整数 x,yx, y1x<y1091 \le x < y \le 10^9),表示每次询问的空区间。

输出格式
对于每次询问,输出一行一个整数,表示最多可以在该区间内停放的列车数量。

样例数据

样例输入

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

样例输出

1
2
1
2

样例解释
在该样例中,共有 33 辆列车,区间分别为 [1,3][1, 3][1,4][1, 4][3,4][3, 4]

  • 第一次询问区间 [1,3][1, 3]:只有第 11 辆列车 [1,3][1, 3] 能够完整停放在该区间内,因此最多停放 11 辆列车。

  • 第二次询问区间 [1,4][1, 4]:可以选择第 11 辆列车 [1,3][1, 3] 和第 33 辆列车 [3,4][3, 4]。这两辆列车在端点 33 处紧贴,且都完整包含在询问区间 [1,4][1, 4] 内,不发生重叠,因此最多停放 22 辆列车。

思路讲解

PDF

2025 United Kingdom and Ireland Programming Contest (UKIEPC 2025) 2025 英国 ICPC——B. Brickwork(判断砖块是否重叠)(扫描线的本质就是遍历一个出一个)(维护一个当前生效的集合)(把二维的问题变为一维的问题来做)

这道题目只要维护一个不相交集合,判断相交即可,而我们这道题目还需整一个这个选择哪些列车摆进来的决策,还是有点难度的。

哈哈,其实这道题目反其道而行之,这道题目的做法是倍增

image

说白了,就是我一次性不放一辆车改为放好多辆车

倍增表使用如下方法生成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void gen_nxt() {
nxt.resize(liSZ, vector<int>(lgSZ + 1, INF));
// 我们可不可以,就是对于每一个位置,我们都能知道,他跳 1<<i 辆列车,可以跳到的 r 点
for (int lay = 0; lay <= lgSZ; ++lay) {
for (int i = 0; i < liSZ; ++i) {
if (lay == 0) {
nxt[i][lay] = dp_mn_r[i];
} else {
if (nxt[i][lay - 1] == INF) continue;
nxt[i][lay] = nxt[nxt[i][lay - 1]][lay - 1];
}
}
}
}

回答也使用这个倍增方法,直接搞出来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int reply_query(int bg, int ed) {
auto [ok,l,r] = compress.projectLr(bg, ed);
if (!ok) return 0;
int cur = l;
int res = 0;
for (int lay = lgSZ; lay >= 0; --lay) {
if (nxt[cur][lay] <= r) {
cur = nxt[cur][lay];
res += (1 << lay);
}
}
return res;
}

AC代码

AC
https://acm.hdu.edu.cn/contest/view-code?cid=1200&rid=14607

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