0%

题目大意

题目描述
给定两个长度为 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……)

题目大意

P16231 [蓝桥杯 2026 省 A] 基因研究

题目描述

DNA 分子的四种碱基分别记为 A、T、G、C。每个人的基因序列都可以认为是一个由 A、T、G、C 四种字符组成的长度为 nn 的字符串。

小蓝正在研究一种疾病。他观察到,这种疾病存在一个固定的易感序列(也可认为是一个由 A、T、G、C 构成的字符串)。若某人的基因序列中存在一个子串恰好等于这个易感序列,则称此人“易感”;若基因序列的任意子串都不等于这个易感序列,则称此人“不易感”。

小蓝希望根据这座城市中人们的基因序列情况,估计出城里“易感”人群所占的比例。

然而,直接获取整座城市中每个人完整的基因序列非常困难。为此,小蓝采用了抽样统计的方法:通过大量采样,他估计出了在这座城市中,每一个位置上碱基为 A、T、G、C 的人数占比。我们可以将其理解为:在所有人的基因序列中,第 ii 个位置为 A、T、G、C 的人数占比分别是多少。

为了简化模型,小蓝作出如下假设:对于任意一个人,其基因序列在每个位置上的碱基分布与采样结果完全一致,且不同位置之间的碱基相互独立。也就是说,即使已经确定了若干个位置上的碱基,剩余位置上的碱基仍然按照对应位置的分布独立生成。

现在,小蓝决定将这些概率以模 998244353998244353 的形式算出:如果“易感”人群所占比例为 pq\frac{p}{q},则小蓝希望得到一个整数 xx,满足 x×qp(mod998244353)x \times q \equiv p \pmod{998244353}。请你根据给定的易感序列,以及每个位置上四种碱基的概率分布,帮小蓝计算并输出这个整数 xx

输入格式

第一行包含两个正整数 n,mn, m,分别表示基因序列长度和易感序列长度。

第二行包含一个长度为 mm 的字符串 ss,仅由 A、T、G、C 构成,表示疾病对应的易感序列。

接下来 nn 行,每行包含四个非负整数 ai,ti,gi,cia_i, t_i, g_i, c_i。其中:

  • aia_i 表示第 ii 个位置碱基为 A 的概率(模 998244353998244353 意义下);

  • tit_i 表示第 ii 个位置碱基为 T 的概率(模 998244353998244353 意义下);

  • gig_i 表示第 ii 个位置碱基为 G 的概率(模 998244353998244353 意义下);

  • cic_i 表示第 ii 个位置碱基为 C 的概率(模 998244353998244353 意义下)。

保证对任意 ii,均有 (ai+ti+gi+ci)mod998244353=1(a_i + t_i + g_i + c_i) \bmod 998244353 = 1

输出格式

输出一行,包含一个非负整数,表示“基因序列中包含易感序列作为子串”的人群占比在模 998244353998244353 意义下的结果。

输入输出样例 #1

输入 #1

1
2
3
4
5
3 2
AA
499122177 499122177 0 0
499122177 0 499122177 0
499122177 0 0 499122177

输出 #1

1
623902721

说明/提示

【样例说明】

基因序列共有 33 个位置:

  • 11 位有 12\frac{1}{2} 的概率是 AA,有 12\frac{1}{2} 的概率是 TT

  • 22 位有 12\frac{1}{2} 的概率是 AA,有 12\frac{1}{2} 的概率是 GG

  • 33 位有 12\frac{1}{2} 的概率是 AA,有 12\frac{1}{2} 的概率是 CC

易感序列为 AAAA。因此,一个人被视为“易感”,当且仅当其基因序列中包含子串 AAAA

所有可能产生的基因序列中,满足条件的共有 3 种,分别是 AACAACTAATAAAAAAAA。这 3 种序列出现的概率均为 18\frac{1}{8},因此“易感”人群所占的总比例为 18+18+18=38\frac{1}{8} + \frac{1}{8} + \frac{1}{8} = \frac{3}{8},其在模 998244353998244353 意义下的结果为 623902721623902721

【评测用例规模与约定】

对于 30%30\% 的数据,1mn51 \le m \le n \le 5

另存在 20%20\% 的数据,ai=ti=gi=cia_i = t_i = g_i = c_i

对于 100%100\% 的数据,1mn3000,0ai,ti,gi,ci<9982443531 \le m \le n \le 3000, 0 \le a_i, t_i, g_i, c_i < 998244353

思路讲解

AC代码

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

题目大意

P16230 [蓝桥杯 2026 省 A] 综合应变指标

题目描述

航空引擎涡轮叶片是确保国家空天安全的核心装备,其制造工艺代表了工业技术的巅峰。

这天,在精密检测实验室的中央,首席结构分析师小蓝正利用高精度传感器,沿涡轮叶片的中轴线进行连续扫描。扫描产生的反馈数据被转化为一条包含 NN 个元素的序列 A=(A1,A2,,AN)A = (A_1, A_2, \dots, A_N)

为了评估叶片在极限运行负载下的稳定性,小蓝需要针对这组序列计算出一个综合应变指标。计算该指标的第一步是选定三个分割点 i,j,ki, j, k(满足 1i<j<k<N1 \le i < j < k < N),将整条序列划分为以下四个连续且非空的子段:

  1. 第一段:A1,,AiA_1, \dots, A_i

  2. 第二段:Ai+1,,AjA_{i+1}, \dots, A_j

  3. 第三段:Aj+1,,AkA_{j+1}, \dots, A_k

  4. 第四段:Ak+1,,ANA_{k+1}, \dots, A_N

第二步,需要计算每一个子段内所有数值的总和,并取其绝对值。这四个绝对值的累加总和被定义为该划分方案下的综合应变指标:

A1++Ai+Ai+1++Aj+Aj+1++Ak+Ak+1++AN |A_1 + \cdots + A_i| + |A_{i+1} + \cdots + A_j| + |A_{j+1} + \cdots + A_k| + |A_{k+1} + \cdots + A_N|

分割点的选择有多种可能,不同的方案会导致不同的指标结果。

现在,请你帮助小蓝找出一种划分方案,使得得到的综合应变指标的数值最大。

输入格式

第一行包含一个正整数 NN,表示扫描序列采集到的反馈节点总数。

第二行包含 NN 个整数 A1,A2,,ANA_1, A_2, \dots, A_N,表示序列的元素。

输出格式

输出一行一个整数,表示序列所能达到的最大综合应变指标。

输入输出样例 #1

输入 #1

1
2
5
1 -1 -2 3 5

输出 #1

1
12

说明/提示

【评测用例规模与约定】

对于 30%30\% 的评测用例,4N1004 \le N \le 100

对于 60%60\% 的评测用例,4N4004 \le N \le 400

对于所有评测用例,4N1054 \le N \le 10^5109Ai109-10^9 \le A_i \le 10^9

思路讲解

PDF

image

写出一个 O(n2)O(n^2) 的 dp 代码没有那么难。

1
2
3
4
5
6
7
void excute_dp(const vector<ll> &dp1, vector<ll> &dp2) {
for (int i = 1; i <= N; ++i) {
for (int j = 1; j <= i; ++j) {
dp2[i] = max(dp2[i], dp1[j] + abs(preA[i] - preA[j]));
}
}
}

现在最关键的就是如何把这个内层的 for 循环给优化掉。

有绝对值?那就要把绝对值去掉,用分类讨论。

说白了,其实就是这样子,因为我们有 max 函数,甚至可以不需要分类讨论。

1
2
3
4
5
6
7
8
void excute_dp(const vector<ll> &dp1, vector<ll> &dp2) {
for (int i = 1; i <= N; ++i) {
for (int j = 1; j <= i; ++j) {
dp2[i] = max(dp2[i], dp1[j] + preA[i] - preA[j]);
dp2[i] = max(dp2[i], dp1[j] - (preA[i] - preA[j]));
}
}
}

AC代码

AC
https://www.luogu.com.cn/record/273684075

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