标签 竞赛 下的文章

abc436 反思

题面

A - o 判定

问题描述

给定一个整数 $ N $ 和一个由小写英文字母组成的字符串 $ S $,其长度小于 $ N $。

请输出通过持续在字符串 $ S $ 的开头添加小写英文字母 o 直到其长度变为 $ N $ 所得到的字符串。

约束条件

  • $ 2 \leq N \leq 100 $
  • $ N $ 为整数
  • $ S $ 是由小写英文字母组成的字符串,长度介于 $ 1 $ 到 $ N-1 $ 之间(包含边界)。

输入格式

输入通过标准输入以如下格式给出:

$$ N $$

$$ S $$

输出格式

输出答案字符串。

样例输入 1

5
abc

样例输出 1

ooabc

解释:$ N=5 $,$ S $ 的长度为 $ 3 $,因此需要在 $ S $ 的开头添加 $ 5 - 3 = 2 $ 个 o。

样例输入 2

2
o

样例输出 2

oo

样例输入 3

12
vgxgpuam

样例输出 3

oooovgxgpuam

B - 幻方阵

问题描述

给定一个大于等于 $ 3 $ 的奇数 $ N $。

有一个 $ N $ 行 $ N $ 列的方格,初始时所有格子均为空白。现在,按照以下步骤在方格中的每个格子上写入整数。
记格子 $ (i, j) $ 表示从上到下第 $ i+1 $ 行、从左到右第 $ j+1 $ 列的格子($ 0 \leq i < N, 0 \leq j < N $)。

  1. 在格子 $ \left(0, \frac{N-1}{2}\right) $ 中写入 $ 1 $。
  2. 重复以下操作 $ N^2 - 1 $ 次:

    • 设上一次写入整数的格子为 $ (r, c) $,写入的整数为 $ k $。如果格子 $ ((r-1) \bmod N, (c+1) \bmod N) $ 是空白的,则在该格子写入 $ k+1 $;否则,在格子 $ ((r+1) \bmod N, c) $ 中写入 $ k+1 $。
    • 这里,$ x \bmod N $ 表示 $ x $ 除以 $ N $ 的余数。

请找出按照此过程在每个格子中写入的整数。
可以证明,每个格子恰好会被写入一个整数。

约束条件

  • $ 3 \leq N \leq 99 $
  • $N$ 是奇数

输入格式

输入通过标准输入以如下格式给出:

$$ N $$

输出格式

设格子 $ (i, j) $ 中写入的整数为 $ a_{i, j} $,并按如下格式输出:

$$ a_{0, 0} \ a_{0, 1} \ \dots \ a_{0, N-1} \\ \vdots \\ a_{N-1, 0} \ a_{N-1, 1} \ \dots \ a_{N-1, N-1} $$

样例输入 1

3

样例输出 1

8 1 6
3 5 7
4 9 2

解释:

  1. 在格子 $ (0, \frac{3-1}{2}) = (0, 1) $ 中写入 $ 1 $。
  2. 格子 $ ((0-1) \bmod 3, (1+1) \bmod 3) = (2, 2) $ 是空白的,因此写入 $ 2 $。
  3. 格子 $ ((2-1) \bmod 3, (2+1) \bmod 3) = (1, 0) $ 是空白的,因此写入 $ 3 $。
  4. 格子 $ ((1-1) \bmod 3, (0+1) \bmod 3) = (0, 1) $ 非空白,因此在格子 $ ((1+1) \bmod 3, 0) = (2, 0) $ 中写入 $ 4 $。
  5. 依此类推……

样例输入 2

5

样例输出 2

17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9

C - 放置 2×2 方块

问题描述

有一个 $ N $ 行 $ N $ 列的方格。记格子 $ (i, j) $ 表示从上到下第 $ i $ 行、从左到右第 $ j $ 列的格子。初始时,方格上没有任何方块。

现在将进行 $ M $ 次操作。第 $ i $ 次操作($ 1 \leq i \leq M $)如下:

  • 将以格子 $ (R_i, C_i) $ 为左上角的 $ 2 \times 2 $ 区域的方块放置到方格上,当且仅当该区域与已放置的其他方块不重叠。
    更精确地说,对于单元格集合 $ S = \{ (R_i, C_i), (R_i+1, C_i), (R_i, C_i+1), (R_i+1, C_i+1) \} $,如果方格上已存在的方块占据了 $ S $ 中的任意一个格子,则什么也不做;否则,放置一个占据 $ S $ 中全部 4 个格子的方块。

请计算所有操作结束后,方格上共有多少个方块。

约束条件

  • $ 2 \leq N \leq 10^9 $
  • $ 1 \leq M \leq 2 \times 10^5 $
  • $ 1 \leq R_i, C_i \leq N-1 $
  • 输入均为整数

输入格式

输入通过标准输入按以下格式给出:

$$ N \ M $$

$$ R_1 \ C_1 $$

$$ R_2 \ C_2 $$

$$ \vdots $$

$$ R_M \ C_M $$

输出格式

输出答案。

样例输入 1

4 3
1 1
2 2
2 3

样例输出 1

2

解释:
下图展示了操作过程,黑色填充区域表示方块,红色边框区域表示下一个要放置方块的位置。
abc436_c.png

  1. 操作 1:以格子 $ (1, 1) $ 为左上角的 $ 2 \times 2 $ 区域为空,因此放置方块。
  2. 操作 2:以格子 $ (2, 2) $ 为左上角的 $ 2 \times 2 $ 区域中,格子 $ (2, 2) $ 已被占据,因此什么也不做。
  3. 操作 3:以格子 $ (2, 3) $ 为左上角的 $ 2 \times 2 $ 区域为空,因此放置方块。

因此,所有操作结束后,方格上有 2 个方块。

样例输入 2

1000000000 4
1 1
1 101
101 1
101 101

样例输出 2

4

所有操作都可以放置方块。

样例输入 3

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

样例输出 3

8

可能存在满足 $ (R_i, C_i) = (R_j, C_j) $ 的 $ i, j $($ i \neq j $)。


D - 传送迷宫

问题描述

有一个迷宫,由 $ H $ 行 $ W $ 列的网格构成。记格子 $ (i, j) $ 表示从上到下第 $ i $ 行、从左到右第 $ j $ 列的格子。格子 $ (i, j) $ 的类型由字符 $ S_{i, j} $ 给出,每个字符的含义如下:

  • .:空单元格
  • #:障碍单元格
  • 小写英文字母(a - z):传送单元格

在迷宫中,你可以按任意顺序执行以下两种类型的操作任意多次:

  1. 步行:从当前单元格移动到上下左右四个方向相邻的单元格。但是,不能移动到障碍单元格或网格外。
  2. 传送:当你处于一个传送单元格时,可以移动到写有相同字母的任意传送单元格。

判断是否可以从单元格 $ (1, 1) $ 移动到单元格 $ (H, W) $,如果可能,求出所需的最小总操作次数。

约束条件

  • $ 1 \leq H, W \leq 1000 $
  • $ H \times W \geq 2 $
  • $ H $ 和 $ W $ 为整数
  • $ S_{i, j} $ 是 .、# 或小写英文字母
  • $ S_{1, 1} \neq \# $
  • $ S_{H, W} \neq \# $

输入格式

输入通过标准输入按以下格式给出:

$$ H \ W $$

$$ S_{1, 1} \ S_{1, 2} \ \dots \ S_{1, W} $$

$$ \vdots $$

$$ S_{H, 1} \ S_{H, 2} \ \dots \ S_{H, W} $$

输出格式

如果可以从单元格 $ (1, 1) $ 移动到单元格 $ (H, W) $,输出所需的最小总操作次数;否则输出 -1。

样例输入 1

3 4
..a.
####
ba#b

样例输出 1

5

解释:
可以通过以下操作从单元格 $ (1, 1) $ 移动到单元格 $ (3, 4) $:

  1. 从 $ (1, 1) $ 步行到 $ (1, 2) $
  2. 从 $ (1, 2) $ 步行到 $ (1, 3) $
  3. 从 $ (1, 3) $ 传送到 $ (3, 2) $
  4. 从 $ (3, 2) $ 步行到 $ (3, 1) $
  5. 从 $ (3, 1) $ 传送到 $ (3, 4) $

总操作次数为 $ 5 $,这是最小值。

样例输入 2

3 4
..a.
####
b.#b

样例输出 2

-1

无法从单元格 $ (1, 1) $ 移动到单元格 $ (3, 4) $。

样例输入 3

4 4
xxxx
xxxx
xxxx
xxxx

样例输出 3

1

样例输入 4

7 11
u..#y..#...
k..#.z.#.k.
iju#...#x..
###########
..x#.t.#..n
abc#y..#...
..z#..t#.y.

样例输出 4

12

E - 最小交换次数

问题描述

给定一个整数序列 $ P = (P_1, P_2, \dots, P_N) $,它是 $ (1, 2, \dots, N) $ 的一个排列。这里保证 $ P $ 不等于 $ (1, 2, \dots, N) $。

你想要执行零次或多次以下操作,使 $ P $ 匹配序列 $ (1, 2, \dots, N) $:

  • 选择一对整数 $ (i, j) $ 满足 $ 1 \leq i < j \leq N $。交换 $ P_i $ 和 $ P_j $ 的值。

设 $ K $ 为使 $ P $ 匹配序列 $ (1, 2, \dots, N) $ 所需的最少操作次数。

找出可以作为第一次操作的操作数量,使得存在一个操作序列能在 $ K $ 次操作内使 $ P $ 匹配序列 $ (1, 2, \dots, N) $。当且仅当选择的整数对 $ (i, j) $ 不同时,两个操作被视为不同。

约束条件

  • $ 2 \leq N \leq 3 \times 10^5 $
  • $ 1 \leq P_i \leq N $($ 1 \leq i \leq N $)
  • $ P_i \neq P_j $($ 1 \leq i < j \leq N $)
  • 存在 $ 1 \leq i \leq N $ 使得 $ i \neq P_i $
  • 所有输入值均为整数

输入格式

输入通过标准输入按以下格式给出:

$$ N $$

$$ P_1 \ P_2 \ \dots \ P_N $$

输出格式

输出答案。

样例输入 1

5
3 1 4 2 5

样例输出 1

6

例如,可以通过以下三次操作达成目标:

  1. 选择 $ (i, j) = (1, 2) $。$ P $ 变为 $ (1, 3, 4, 2, 5) $
  2. 选择 $ (i, j) = (2, 4) $。$ P $ 变为 $ (1, 2, 4, 3, 5) $
  3. 选择 $ (i, j) = (3, 4) $。$ P $ 变为 $ (1, 2, 3, 4, 5) $

无法在两次或更少操作内达成目标,因此 $ K = 3 $。

如上所述,第一次操作选择 $ (1, 2) $ 可以在三次操作内达成目标。此外,如果第一次操作选择 $ (1, 3) $、$ (1, 4) $、$ (2, 3) $、$ (2, 4) $、$ (3, 4) $ 中的任意一个,那么通过适当执行接下来的两次操作,也可以使 $ P $ 变为 $ (1, 2, 3, 4, 5) $。

因此,输出 6。

样例输入 2

2
2 1

样例输出 2

1

样例输入 3

20
15 5 13 17 9 11 20 4 14 16 6 3 8 19 12 7 10 18 2 1

样例输出 3

77

F - 星空风景照

问题描述

在从 AtCoder 星球看到的夜空中,有 $ N $ 颗星星,这些星星自东向西排成一条直线。从东数第 $ i $ 颗星星($ 1 \leq i \leq N $)是这些星星中第 $ B_i $ 亮的。

Takahashi 决定用以下步骤拍摄夜空:

  1. 选择一对整数 $ (l, r) $ 满足 $ 1 \leq l \leq r \leq N $,并调整相机,使得从东数第 $ l $ 颗、第 $ (l+1) $ 颗、…、第 $ r $ 颗星星全部进入取景框,且没有其他星星进入取景框。
  2. 选择一个整数 $ b $ 满足 $ 1 \leq b \leq N $,并打开快门,使得所有 $ N $ 颗星星中亮度排名在第 1 到第 $ b $ 位(且在取景框内)的星星被拍摄到,其他星星不被拍摄。
    但是,他不能拍摄没有星星被捕捉到的照片。

求用这种方式拍摄的照片中,可以捕捉到的星星的不同集合的数量。

约束条件

  • $ 1 \leq N \leq 5 \times 10^5 $
  • $ 1 \leq B_i \leq N $($ 1 \leq i \leq N $)
  • $ B_i \neq B_j $($ 1 \leq i < j \leq N $)
  • 所有输入值均为整数

输入格式

输入通过标准输入按以下格式给出:

$$ N $$

$$ B_1 \ B_2 \ \dots \ B_N $$

输出格式

输出答案。

样例输入 1

4
3 1 4 2

样例输出 1

12

例如,当 $ (l, r) = (2, 4) $,$ b = 3 $ 时,你可以拍摄包含两颗星星的照片:从东数第 2 颗星星和第 4 颗星星。

包括这个在内,你可以拍摄以下 12 种不同的星星集合。每张照片中,较东的星星排在较左边,第 $i$ 亮的星星用整数 $i$ 标记。
abc436_f.png

没有其他集合可以被捕捉,因此输出 12。

样例输入 2

7
1 2 3 4 5 6 7

样例输出 2

28

样例输入 3

20
15 5 13 17 9 11 20 4 14 16 6 3 8 19 12 7 10 18 2 1

样例输出 3

627

G - 线性不等式

问题描述

给定一个长度为 $ N $ 的正整数序列 $ A = (A_1, A_2, \dots, A_N) $ 和一个正整数 $ M $。

求满足以下条件的非负整数序列 $ x = (x_1, x_2, \dots, x_N) $ 的数量:

$$ \sum_{i=1}^{N} A_i x_i \leq M $$

由于该数量可能非常大,请输出其对 $ 998244353 $ 取模的结果。

约束条件

  • $ 1 \leq N \leq 100 $
  • $ 1 \leq A_i \leq 100 $($ 1 \leq i \leq N $)
  • $ 1 \leq M \leq 10^{18} $
  • 所有输入值均为整数

输入格式

输入通过标准输入按以下格式给出:

$$ N \ M $$

$$ A_1 \ A_2 \ \dots \ A_N $$

输出格式

输出满足条件的非负整数序列的数量(对 $ 998244353 $ 取模)。

样例输入 1

4 6
5 4 3 2

样例输出 1

10

满足条件的序列 $ x $ 有以下 10 个:
$ (0,0,0,0) $, $ (0,0,0,1) $, $ (0,0,0,2) $, $ (0,0,0,3) $, $ (0,0,1,0) $, $ (0,0,1,1) $, $ (0,0,2,0) $, $ (0,1,0,0) $, $ (0,1,0,1) $, $ (1,0,0,0) $。

因此,输出 10。

样例输入 2

6 89
4 7 5 10 7 6

样例输出 2

38469

样例输入 3

1 1000000007
1

样例输出 3

1755655

满足条件的序列 $ x $ 有 $ 1000000008 $ 个。

输出其对 $ 998244353 $ 取模的结果,即 $ 1755655 $。

样例输入 4

20 738894495848985641
40 58 13 24 65 11 63 29 98 75 40 77 15 50 83 85 35 46 38 37

样例输出 4

31156940

反思

A - o 判定

这是一道水题,但我只会做水题
整理一下题意,意思就是说给出 $N$ 和 $S$,输出 $N-S_{size}$ 个 o 用于补全,然后再输出原来的字符串 $S$
时间复杂度:$O(N)$,可以通过!
然后就没什么东西了
可能需要注意一下 for 循环的三个语句,到底在做什么:

令 $k$ 为 $N-S_{size}$
若 $N=5 ,\space S=\text{fuck}$
则 $k=N-S_{size}=5-4=1$
所以应该输出 $1$ 个 o
然后再输出完整的 S
#include <bits/stdc++.h>
using namespace std;
int x,i;
string s;
int main(){
    cin>>x>>s;
    for(i=1;i<=x-s.length();i++) cout<<'o';
    cout<<s;
}

就是这样,so easy

B - 幻方阵

这题需要一定的耐心来阅读题面文本。
这题可以直接根据 题目描述 的题进行暴力编写程序,不需要一些复杂的抽象概念思考建模。
我直接贴代码了,毫无技术含量。

#include <bits/stdc++.h>
using namespace std;
int a[100][100],n,r,c,k,nr,nc,i,j;
int main(){
    cin>>n;c=(n-1)/2;
    for(k=1;k<=n*n;k++){
        a[r][c]=k;
        nr=(r-1+n)%n;
        nc=(c+1)%n;
        if(a[nr][nc]!=0) nr=(r+1)%n,nc=c;
        r=nr;
        c=nc;
    }
    for(i=0;i<n;i++){
        for(j=0;j<n;j++){
            cout<<a[i][j];
            if(j<n-1) cout<<" ";
        }
        cout<<"\n";
    }
    return 0;
}

T1

【题面】T678583 A美丽数 (beauty)

题目描述

小 B 对数字有着独到的见解,他认为一个数是美丽数当且仅当这个数的相邻两位都不相同。

例如12345、12121是美丽数,而123321、11不是美丽数。
现在小B想知道,对于所有满足以下条件的数中,最小的那个数是什么?如果不存在这样的美丽数,则输出-1。

· 对 于i(0≤i≤9), 这个数中是i 的位数一共有ai 个。

· 这个数不能有前导0,即012是不合法的。
有多组测试点,每组测试点现在给你a0~a9, 请你回答小B 的问题。

输入格式

第一行包含一个整数T。

接下来T 行,每行10个整数, a0~a9, 含义如题。

输出格式

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

输入输出样例 #1

输入 #1

12
6 0 0 0 0 0 0 0 0 5
0 1 0 2 0 0 0 0 0 0
3 0 0 0 2 0 0 1 0 0
0 1 2 3 4 5 6 7 8 9
1 2 0 1 5 0 1 0 0 0
2 1 1 0 1 5 0 0 0 0
6 0 1 0 2 0 0 0 1 0
8 1 0 0 1 0 0 0 0 0
5 2 0 0 2 0 1 0 0 0
3 0 0 0 0 3 0 2 1 1
3 1 0 5 0 0 1 0 0 0
0 1 2 0 0 1 0 1 0 5

输出 #1

-1
313
404070
123234345454565656767676787897979898989898989
1404143464
1505052545
-1
-1
1010404060
5050507879
1303030363
1929295979

说明/提示

对于100%的数据,保证:T≤10,1≤n,ai≤ 10⁵, 其中$n=∑ai(0≤i≤9)$
测试点编号数据范围特殊性质
1~2n≤10无
3~4n≤10³无
5~6无限制A
7~8无限制B
9~10无限制无

A: 保证最多只有2个ai>0。

B: 保证最多只有3个ai>0。

【代码】T678583 A美丽数 (beauty)

#include <bits/stdc++.h>
using namespace std;
int t,i,d,p,m,c,w,l,g,a[11],cnt[11],f;
string s;
bool j(int t,int b=-1){
    int mx=0;
    for(i=1;i<=10;i++){
        if(i-1==b) continue;
        if(cnt[i]>mx) mx=cnt[i];
    }
    return mx\*2<=t+1;
}
int main(){
    cin>>t;
    while(t--){
        for(i=1;i<=10;i++) cin>>a[i];
        m=c=0;l=-1;s="";
        for(i=1;i<=10;i++) m+=a[i];
        if(m==0){cout<<-1<<"\\n";continue;}
        for(i=1;i<=10;i++) if(a[i]>c) c=a[i];
        if(c>(m+1)/2){cout<<-1<<"\\n";continue;}
        for(i=1;i<=10;i++) cnt[i]=a[i];
        for(p=0;p<m;p++){
            f=0;
            for(d=1;d<=10;d++){
                g=d-1;
                if(cnt[d]==0) continue;
                if(g==l) continue;
                if(p==0&&g==0) continue;
                cnt[d]--;
                if(j(m-p-1,g)){
                    s+=char('0'+g);
                    l=g;
                    f=1;
                    break;
                }
                cnt[d]++;
            }
            if(!f){cout<<-1<<"\\n";break;}
        }
        if(f) cout<<s<<"\\n";
    }
}

URL

【MX-X23】梦熊 X 组 · 月亮赛(同步赛) - 洛谷 | 计算机科学教育新生态

【MX-J26】梦熊 J 组 · 月亮赛(同步赛) - 洛谷 | 计算机科学教育新生态

我的分数

X组:10分

J组:210分

MX-J26/X23 月亮赛 官方题解

A. 丢手绢

小朋友的编号为 $1 \sim n$,直接处理不够便捷,因此将所有编号减去 1,转换为 $0 \sim n-1$。这样调整后,便能通过取模运算轻松计算出每个被放手绢的小朋友编号。

具体规则如下:设编号为 $x$ 的小朋友被记录的数字为 $a_{x}$,则被放手绢的小朋友编号为 $(x + a_{x}) \mod n$。需特别注意,此处涉及负数取模的情况,计算时需遵循相应的取模规则。

后续操作流程为:统计每个小朋友被投放手绢的次数,找出其中的最大值,再依次输出所有出现最大值的小朋友的位置(此处位置需根据最初编号规则还原,若最终结果需对应 $1 \sim n$ 的编号,需将计算得到的 $0 \sim n-1$ 编号加 1)。

该算法的时间复杂度为 $O(n)$,其中 $n$ 为小朋友的总数,仅需遍历一次所有小朋友的记录即可完成统计与计算。

B. 括号序列

首先进行初步判断:若括号序列中左括号和右括号的数量不相等,则该括号序列一定无法构成合法序列,直接判定为无解。接下来仅针对左右括号数量相等的情况展开分析。

判断括号序列是否合法可通过前缀和的方法实现,具体定义前缀和数组 $a_i$ 如下:

$$ a_{i}= \begin{cases} 0, & i=0 \\ a_{i-1}+1, & s_{i}='(' \\ a_{i-1}-1, & s_{i}=')' \end{cases} $$

当遇到相邻的 “)(” 时,将其修改为 “()”,这一操作的本质是将初始时 “)” 对应位置的前缀和加 1,而其他位置的前缀和保持不变。括号序列合法的核心条件是:所有位置的前缀和 $a_i \geq 0$。

基于此条件,判断流程如下:找到第一个满足 $a_i < 0$ 的位置,若该位置附近存在可修改的 “)(” 结构(即能通过修改使该位置及后续位置的前缀和均非负),则进行修改操作,随后再次检查修改后的括号序列是否满足所有前缀和 $a_i \geq 0$,以此确定序列是否合法。

该算法的时间复杂度为 $O(n)$,$n$ 为括号序列的长度,仅需遍历一次序列即可完成前缀和计算与合法性判断。

C. 猜拳游戏

首先定义 $g = \gcd(n, m)$(即 $n$ 和 $m$ 的最大公约数),并令 $n' = \frac{n}{g}$,$m' = \frac{m}{g}$。

在猜拳游戏中,$10100$ 是一个足够大的数字(其值超过 $\text{lcm}(n, m)$,即 $n$ 和 $m$ 的最小公倍数),因此只需考虑游戏不断进行过程中可能出现的所有状态。

将字符串 $a$(长度为 $n$)和字符串 $b$(长度为 $m$)分别按照下标对 $g$ 取模的余数进行分组,共可分为 $g$ 组。以第 $k$ 组($0 \leq k < g$)为例,字符串 $a$ 中属于该组的有 $n'$ 个招式,字符串 $b$ 中属于该组的有 $m'$ 个招式,这两组招式两两组合形成的 $n' \times m'$ 种情况,一定会在同一局游戏中全部出现。

若要避免平局,必须保证字符串 $a$ 中该组的 $n'$ 个招式组成的集合与字符串 $b$ 中该组的 $m'$ 个招式组成的集合没有交集(即两组招式完全不同)。

接下来需讨论 “石头(R)、剪刀(P)、布(S)” 这三种招式在字符串 $a$ 和 $b$ 中的可选情况,在所有合法的情况中选择操作次数最少的方案,最后将 $g$ 组的最少操作次数相加,得到最终的答案。

该算法的时间复杂度为 $O(n + m)$,其中 $n$ 和 $m$ 分别为字符串 $a$ 和 $b$ 的长度,需分别遍历两个字符串完成分组与招式集合的判断。

D. 卡常数

首先分析单个数列的情况:对于某一数列,选择其中一个位置 $j$,会使该数列的代价乘以系数 $\frac{a_{i,j} - b_{i,j}}{a_{i,j}}$(其中 $a_{i,j}$ 和 $b_{i,j}$ 为该数列第 $j$ 个元素的相关参数)。由于该系数为真分数,将数列中所有这样的真分数按照从小到大的顺序排列后,从左到右选择这些真分数(即优先选择较小的真分数),能使数列代价的减少量最大,是最优的选择策略。

进一步计算每个数列中,按照上述顺序选择每个元素时,该元素能让数列代价比选择上一个元素后再减少的量,将这个减少量定义为该元素的“价值”。通过分析可发现,在同一个数列中,元素的价值是单调递减的(即越靠后选择的元素,其减少代价的能力越弱)。

基于单个数列的价值特性,将所有数列中所有元素的价值整合到一个集合中,对该集合按照从大到小的顺序排序,然后依次选择价值最大的元素,即可实现整体代价的最小化。

贪心策略正确性证明:由于单个数列内部元素的价值单调递减,后续元素的价值必然小于前面元素的价值,因此在选择时,后续元素不可能先于前面元素被选中,这就保证了将所有元素价值排序后从大到小选择的贪心策略是正确的。

设 $m = \sum l_i$(其中 $l_i$ 为第 $i$ 个数列的长度),则该算法的时间复杂度为 $O(m \log m)$,主要耗时在于对所有元素价值的排序操作。

E. 向死存魏

首先采用离线处理的方式,将所有的“二操作”(具体操作含义需结合题目背景,此处默认是对序列的修改或查询操作)加入到操作序列中。在执行操作的过程中,实时记录当前序列的长度,若某一查询操作要求的答案超过当前序列的长度,则判定该查询无解。设所有操作全部结束后,序列的最终长度为 $k$。

对于删除操作,由于每个元素至多被删除一次,且序列的最终长度为 $k$,因此可使用 $set$ 数据结构对序列进行暴力修改(如标记删除或直接移除元素),操作效率可满足需求。

对于查询操作,首先利用双指针法预处理出初始状态下从序列每个位置开始查询的答案。在后续的删除操作中,针对被删除的元素 $x$,先确定其删除区间:设删除区间左边第一个未被删除的位置为 $p$(若不存在这样的位置,则令 $p = 0$),删除区间右边第一个未被删除的位置为 $q$(若不存在这样的位置,则令 $q = k + 1$)。删除该区间内所有的 $x$ 后,会对起始位置在 $[p + 1, q - 1]$ 范围内的查询产生影响——从这些起始位置开始查询时,需要到位置 $q$ 才能找到元素 $x$。

为高效处理上述区间影响,需对 $[p + 1, q - 1]$ 范围内的当前查询答案进行更新(将答案设为 $q$),此处可使用线段树维护“区间取最值、单点查询”的操作,确保查询与更新的效率。

该算法的时间复杂度为 $O((k + m) \log k)$,其中 $k$ 为序列最终长度,$m$ 为操作总数,线段树的查询与更新操作均为 $O(\log k)$ 复杂度,且需处理 $m$ 次操作。

F. 网格 III

在网格操作中,每一次操作至多会影响 $O(n)$ 个格子($n$ 为网格的边长或相关维度参数),因此只需关注当前操作实际改变的格子数量即可。

由于行列混合操作较为复杂,可将其拆分为两个独立的部分讨论:一是计算有多少行对当前列的修改产生贡献,二是计算有多少列对当前行的修改产生贡献。下文以“计算行对当前列修改的贡献”为例展开分析。

首先为每行和每列分别记录两个关键信息:最后一次修改的时间、最后一次修改的颜色(如红色或白色)。对于网格中 $k \times k$ 的正方形区域,其对应的所有行列信息仅存在两种不同的有效情况:

  1. 该正方形区域内所有列的修改颜色均为红色,且最晚的白色行修改时间在最早的红色列修改时间之前;
  2. 该正方形区域内存在列的修改颜色为白色,且所有行的修改颜色均为红色,同时最早的红色行修改时间在最晚的白色列修改时间之后。

由于 $k$ 的取值较小,可直接枚举包含当前列且长度为 $k$ 的区间,暴力查询该区间内的行列信息,进而统计满足上述两种情况的行的数量。为提高效率,对于每行,预先记录所有长度为 $k$ 的区间的信息,每次修改操作仅会改变 $O(k)$ 个区间的信息,后续可通过一维偏序的方法查询满足条件的行数量。

为简化时间与颜色的判断逻辑,对修改时间进行如下处理:若修改颜色为红色,时间值保持不变;若修改颜色为白色,时间值取其相反数。初始状态下,所有行列的修改颜色默认为红色,时间值可设为初始常量(如 0)。经过这样的处理,上述两种情况的判断可转化为对区间内时间值取最小值的操作。

可使用树状数组或线段树维护区间最小值,若直接暴力求区间最小值,算法的时间复杂度为 $O(n k^2 + n k \log n)$;若采用单调队列对区间最小值查询进行优化,时间复杂度可降至 $O(n k \log n)$,其中 $n$ 为网格的相关维度参数,$k$ 为正方形区域的边长。

G. 我爱数数

设 $t_i$ 表示使 $b_i \geq a_i$ 所需的操作次数($a_i$ 和 $b_i$ 为题目给定的数组元素),则本题的答案等价于求 $E[\max_{i=1}^{n} t_i]$(即 $t_i$ 最大值的期望)。

可通过容斥原理计算该期望,具体公式为:答案等于对所有非空子集 $S \subseteq [n]$,求和 $(-1)^{|S| - 1} \times E[\min_{i \in S} t_i]$(其中 $|S|$ 表示子集 $S$ 的元素个数,$E[\min_{i \in S} t_i]$ 表示子集 $S$ 中 $t_i$ 最小值的期望)。

期望计算分析

假设有 $x$ 个区间满足:对任意 $i \in [l_p, r_p] \cap S$,均有 $c_p < a_i$($[l_p, r_p]$ 为区间的左右端点,$c_p$ 为区间的相关参数)。此时,剩余的 $m - x$ 个区间($m$ 为总区间数)一旦被选中,就会覆盖子集 $S$ 中的某个元素,导致 $t_i$ 的值固定。

在上述假设下,$E[\min_{i \in S} t_i]$ 的计算过程如下:

$$ E[\min_{i \in S} t_i] = \sum_{i=0}^{+\infty} \frac{x^i (m - x) (i + 1)}{m^{i + 1}} = \frac{m}{m - x} $$

基于此,定义 $w_x$ 为:对所有满足“恰好有 $x$ 个区间符合上述条件”的子集 $S$,求和 $(-1)^{|S| - 1}$。则最终答案可表示为:

$$ \text{答案} = \sum_{x=0}^{m - 1} w_x \times \frac{m}{m - x} $$

动态规划与优化

为计算 $w_x$,引入辅助函数 $h_i$,定义如下:

$$ h_i = \begin{cases} a_i - 1 & i \in S \\ +\infty & \text{Otherwise} \end{cases} $$

此时,“对任意 $i \in [l_p, r_p] \cap S$,$c_p < a_i$”这一限制条件可转化为“对任意 $i \in [l_p, r_p]$,$c_p \leq h_i$”。

进一步构建小根笛卡尔树(基于 $h_i$ 的值),并在树上进行动态规划。定义状态 $f_{L, R, u, x, 0/1}'$,其含义为:

  • 考虑区间 $[L, R]$,仅关注 $h_i \geq u$ 的位置,且 $[L, R]$ 是一个连续段(即 $h_{L - 1} < u$ 且 $h_{R + 1} < u$);
  • 满足 $L \leq l_p \leq r_p \leq R$ 且 $c_p \leq x \leq \min_{i \in [l_p, r_p]} h_i$ 的区间 $p$ 共有 $x$ 个;
  • 子集 $T = S \cap [L, R]$ 的元素个数为偶数(对应“0”)或奇数(对应“1”);
  • 该状态的值表示满足上述条件的子集 $T$ 的数量。

令 $f_{L, R, u, x} = f_{L, R, u, x, 0}' - f_{L, R, u, x, 1}'$,并引入辅助数组 $g$,则动态规划的转移公式如下:

$$ g_{L, R, u, x} = f_{L, R, u + 1, x} - \sum_{i=L}^{R} [h_i = u] \sum_{y=0}^{x} f_{L, i - 1, u + 1, y} \times g_{i + 1, R, u, x - y} $$

$$ f_{L, R, u, x} = g_{L, R, u, x - s_{L, R, u}} $$

其中 $s_{L, R, u}$ 表示满足 $L \leq l_p \leq r_p \leq R$ 且 $c_p = u$ 的区间 $p$ 的数量。

时间复杂度优化

若直接按照上述转移公式计算,时间复杂度为 $O(n^4 m^2)$($n$ 为数组长度,$m$ 为总区间数)。但通过观察可知,$h_i = u$ 的位置对于所有 $u$ 而言,总数仅为 $n$ 个,因此可将时间复杂度优化至 $O(n^3 m^2)$。

进一步利用经典的拉格朗日插值(拉插)技巧,可将转移过程中的卷积运算转化为点乘运算,此时时间复杂度可降至 $O(n^3 m + m^2)$。关于拉格朗日插值技巧的具体应用,可参考题目 CF1874E Jellyfish and Hack。

我的评价

首先,让我吐槽一下这次比赛XJ的题目分配

题目分配

MX-J+XABCDEFG
洛谷T1T2T3T4T5T6T7
MX-J26√√√√√
MX-X23 √√√√√
知识点入门入门入门提高提高NOINOI

开始吐槽

在我的印象里,CSP-X是小学组的难度,但是,这里为什么X组的难度有NOI,我就感觉很猎奇,而且,为什么J组的第一二题在X组没,Who can tell me?

关于各题

【MX-X23-T1】丢手绢

这道题我大概提交了有好几次,主要是老是TLE,原因是因为写了太多没用的循环,这是AC的代码

#include <bits/stdc++.h>
using namespace std;
const int N=100010;
int n,x,i,f[N],ma,s;
int main(){
    cin>>n;
    for(i=1;i<=n;i++){
        cin>>x;s=i+x;
        while(s<1) s+=n;
        while(s>n) s-=n;
        f[s]++;
        ma=max(ma,f[s]);
    }
    for(i=1;i<=n;i++) if(f[i]==ma) cout<<i<<" ";
}

注意超n和小1的数据处理

【MX-X23-T2】括号串

这道题,我当时是在洛谷搜一道题,叫做括号串匹配,然后,找到了,但是没用,然后我在CSXX上找答案,找到了,但是没用

所以只好独立思考

namespace pts70{
bool check(string s){
    int tmp,i;
    for(i=tmp=0;i<s.length();i++){
        if(s[i]=='(') tmp++;
        else if(s[i]==')'){
            tmp--;
            if(tmp<0) return 0;
        }
    }
    return tmp==0;
}
int main(){
    cin>>T;
    while(T--){
        cin>>n>>s;fl1=0;
        if(check(s)) fl1=1;
        if(n>1000){cout<<(fl?"Yes":"No")<<"\n";continue;}
        ss=s;
        for(i=0;i<ss.length()-1;i++){
            ss=s;
            if(ss[i]==')'&&ss[i+1]=='('){
                ss[i]='(';ss[i+1]=')';
                if(check(ss)) fl=1;
                else ss=s;
            }
        }
        cout<<(fl?"Yes":"No")<<"\n";
    }
    return 0;
}
}

思路其实也很明显了,就是死暴力,check函数就是判断这个字符串的括号是否合法,然后,20-29行就是两个字符串一个一个往后做,替换,然后判断,可以就输出,不可以就下一个

测试点编号结果时间内存
1AC4ms788.00KB
2AC4ms788.00KB
3AC4ms832.00KB
4AC8ms788.00KB
5AC8ms832.00KB
6AC34ms788.00KB
7AC33ms788.00KB
8WA32ms788.00KB
9WA32ms788.00KB
10WA34ms788.00KB

然后我看了一眼前面那个人的代码,发现是我想多了,代码

#include <bits/stdc++.h>
using namespace std;
const int N=100010;
int T,n,t,w,wz,i,fl1,fl2,sts;
char s[N];
void count(){
    if(s[i]=='(') t++;
    if(s[i]==')') w++;
}
int main(){
    cin>>T;
    while(T--){
        cin>>n;t=w=0;fl1=1;
        for(i=1;i<=n;i++){
            cin>>s[i];
            count();
            if(t<w){fl1=0;wz=i;}
        }
        if(t==w){
            sts=1;
            if(fl1==1){cout<<"Yes\n";sts=0;continue;}
            swap(s[wz],s[wz+1]);
            t=w=0;fl2=1;
            for(i=1;i<=n;i++){
                count();
                if(t<w) fl2=0;
            }
            if(wz==n) fl2=0;
            if(sts==1) cout<<(fl2?"Yes":"No")<<"\n";
        }else{cout<<"No\n";continue;}
    }
}

【MX-X23-T3】猜拳游戏

不会做,这个代码 10pts

#include <bits/stdc++.h>
using namespace std;

int main(){
    cout<<1;
}

试题

上海市2025CSP-J十连测Round 7.pdf

大感

我们这一次并没有批分数,所以关于上海市2025CSP-J十连测Round 7的内容我们会分为$Part 1$和$Part 2$
这一次我估计很难

上海市2025CSP-J十连测Round 7 题干

一、单项选择题

共15题、每题2分,共计30分,每题有且仅有一个正确选项。

  1. 如果开始时计算机处于小写输入状态,现在有一只小老鼠反复按照CapsLock、字母键A、字母键S和字母键D的顺序循环按键,即CapsLock、A、S、D、CapsLock、A、S、D……则屏幕上输出的第2025个字符是字母()。
    A. A
    B. S
    C. D
    D. a
  2. 在8位二进制补码中,10101011表示的是十进制下的()。
    A. -85
    B. -43
    C. 43
    D. 85
  3. 给定一个含N个不相同数字的数组,在最坏情况下,找出其中最大或最小的数,至少需要$N-1$次比较操作。则最坏情况下,在该数组中同时找最大与最小的数至少需要()次比较操作。(「」表示向上取整,⌊⌋表示向下取整)
    A. $\left\lceil\frac{3N}{2}\right\rceil - 2$
    B. $\left\lfloor\frac{3N}{2}\right\rfloor - 2$
    C. $2N - 2$
    D. $2N - 4$
  4. 表达式$a*(b+c)-d$的后缀表达形式为()。
    A. $abc d*+-$
    B. $abc+*d-$
    C. $abc*+d-$
    D. $-+*abcd$
  5. 约定二叉树的根节点高度为1。一棵结点数为2025的二叉树最少有()个叶子结点;一棵结点数为2025的二叉树最小的高度值是()。
    A. 1,11
    B. 1,12
    C. 2,11
    D. 2,12
  6. 向一个栈顶指针为$hs$的链式栈中插入一个指针s指向的结点时,应执行()。
    A. $hs \to next = s;$
    B. $s \to next = hs; hs = s;$
    C. $s \to next = hs \to next; hs \to next = s;$
    D. $s \to next = hs; hs = hs \to next$
  7. 2-3树是满足两个条件的树:①所有叶结点到根的路径长度相同;②所有非叶子结点有两个或三个子结点。如果一棵2-3树有10个叶结点,那么它可能有()个非叶结点。
    A. 3
    B. 4
    C. 6
    D. 8
  8. 由四个没有区别的点构成的简单无向连通图的个数是()。
    A. 6
    B. 7
    C. 8
    D. 9
  9. 设含有10个元素的集合的全部子集数为S,其中由7个元素组成的子集数为T,则$\frac{T}{S}$的值()。
    A. $\frac{5}{32}$
    B. $\frac{15}{128}$
    C. $\frac{1}{8}$
    D. $\frac{21}{125}$
  10. 如下图所示,共有13个格子。对任何一个格子进行一次操作,会使得它自己以及与它上下左右相邻的格子中的数字改变(由1变0,或由0变1)。现在要使得所有的格子中的数字都变为0,至少需要()次操作。
    A. 3
    B. 4
    C. 5
    D. 6
  11. 一个1×8的方格图形(不可旋转)用黑、白两种颜色填涂每个方格。如果每个方格只能填涂一种颜色,且不允许两个黑格相邻,共有()种填涂方案。
    A. 8
    B. 55
    C. 56
    D. 64
  12. 设G是有n个结点、m条边($n \leq m$)的连通图,必须删去G的()条边,才能使得G变成一棵树。
    A. $m - n + 1$
    B. $m - n$
    C. $m + n + 1$
    D. $n - m + 1$
  13. 有7个一模一样的苹果,放到3个一样的盘子中,一共有()种放法。
    A. 7
    B. 8
    C. 21
    D. 2187
  14. 若$f_0 = 0$,$f_1 = 1$,$f_{n+1} = \frac{f_n + f_{n-1}}{2}$,则随着i的增大,$f_i$将接近于()。
    A. $\frac{1}{2}$
    B. $\frac{2}{3}$
    C. $\frac{\sqrt{5} - 1}{2}$
    D. 1
  15. 以下是32位机器和64位机器的区别是()。
    A. 显示器不同
    B. 硬盘大小不同
    C. 寻址空间不同
    D. 输入法不同

二、阅读程序

判断题1分,选择题3分,共计40分;判断题正确填T,错误填F。

第1题

int solve1(int n) {
    n++;
    int size = 0;
    int digit[16];
    int pow = 1;
    int s = 0;
    while (n > 0) {
        digit[size] = n % 10;
        size++;
        n /= 10;
        s += pow;
        pow *= 5;
    }
    while (size > 0) {
        --size;
        pow /= 5;
        s += (digit[size] / 2) * pow;
        if (digit[size] % 2 == 0) break;
    }
    return s - 1;
}

int solve2(int n) {
    int s = 0;
    for (int i = 1; i <= n; i += 2) {
        int t = i;
        bool pass = true;
        while (t > 0) {
            int x = t % 10;
            if (x % 2 == 0) {
                pass = false;
                break;
            }
            t /= 10;
        }
        if (pass) s++;
    }
    return s;
}

保证solve1与solve2的参数n是非负整数。

判断题

  1. solve1(11)的返回值为6()。
  2. solve2(12345)的返回值为906()。
  3. 对所有的$n > 0$,必有solve1(n) <= n()。
  4. solve1(0)的返回值为0()。

选择题

  1. 关于solve1(n)与solve2(n)的大小关系,当$n \geq 0$时,下列说法正确的是()。
    A. 必然有solve1(n) < solve2(n)
    B. 必然有solve1(n) == solve2(n)
    C. 只有当n为偶数时,才有solve1(n) = solve2(n)
    D. 只有当n为奇数时,才有solve1(n) == solve2(n)
  2. 若将solve1函数中第一句n++去掉,将solve2函数中for循环的i += 2改为i += 1,则新返回值与原来相比()。
    A. solve1不变,solve2变大
    B. solve1不变,solve2变小
    C. solve1变小,solve2不变
    D. solve1变大,solve2不变
  3. solve1(n)与solve2(n)的时间复杂度为()。
    A. $\Theta(logn)$、$\Theta(logn^2)$
    B. $\Theta(logn)$、$\Theta(n)$
    C. $\Theta(logn)$、$\Theta(nlogn)$
    D. $\Theta(n)$、$\Theta(n^2)$

第2题

int a[maxn];
int b[maxn];
int n, m;
const long long mod = 1000000007;
bool filled[maxn][maxn];
long long mem[maxn][maxn];

long long solve(int i, int j) {
    if (filled[i][j]) return mem[i][j];
    if (i == n) return 1;
    if (j == m) return 1;
    filled[i][j] = true;
    if (a[i] == b[j]) {
        long long sum = solve(i + 1, j) + solve(i, j + 1);
        return mem[i][j] = sum % mod;
    } else {
        return mem[i][j] = (solve(i + 1, j) - solve(i + 1, j + 1)) % mod;
    }
}

int main() {
    std::cin >> n >> m;
    for (int i = 0; i < n; ++i) std::cin >> a[i];
    for (int i = 0; i < m; ++i) std::cin >> b[i];
    std::cout << (solve(0, 0) + mod) % mod << "\n";
}

判断题

  1. 若依次输入数据2 2 1 3 3 1,程序返回的结果是3()。
  2. 如果$n = 0$或$m = 0$,程序返回的结果是1()。
  3. 如果两个序列完全相同,程序返回的结果是$2^n$()。
  4. 输出时,执行solve(0,0)+mod是多余的运算()。

选择题

  1. 该程序的主要功能是()。
    A. 计算两个序列的最长公共子序列的长度
    B. 计算两个序列的公共子序列的数量
    C. 计算两个序列的公共子串的数量
    D. 计算两个序列的相同元素个数
  2. 该程序的时间复杂度为()。
    A. $\Theta(n + m)$
    B. $\Theta(n \cdot m)$
    C. $\Theta(2^{m + n})$
    D. $\Theta(nlogm)$
  3. 当$a[i] = b[j]$时,返回值需要减去solve(i+1,j+1)的原因是()。
    A. 排除重复情况
    B. 排除错误情况
    C. 优化程序的空间效率
    D. 优化程序的时间效率

第3题

long long k;
int n;
int p[20];
bool used[20] = {false};
long long frac[20];

void gen(int i) {
    if (i > n) {
        for (int i = 1; i <= n; ++i) std::cout << p[i] << " ";
        return;
    }
    for (int a = 1; a <= n; ++a) if (!used[a]) {
        if (k <= frac[n - i]) {
            p[i] = a;
            used[a] = true;
            gen(i + 1);
            return;
        } else {
            k -= frac[n - i];
        }
    }
}

int main() {
    n = 1;
    std::cin >> k;
    frac[0] = frac[1] = 1;
    while (k > frac[n]) {
        k -= frac[n];
        frac[n + 1] = frac[n] * (n + 1);
        n++;
    }
    gen(1);
}

判断题

  1. 当输入k为1时候,输出1()。
  2. 当输入k为1000时候,输出1 5 2 4 3()。

选择题

  1. 关于程序输出的序列所满足的性质,错误的是()。
    A. 输出的每个数字各不相同
    B. 输出的数字都在1到n之间
    C. 输出的相邻的数字差距不会超过1
    D. 最先输出的数字在程序中是最先被确定的
  2. 下列说法正确的是()。
    A. 越大的k一定会输出越长的序列
    B. k若是奇数,输出序列的长度一定也是奇数
    C. 程序的时间复杂度为(k!)
    D. gen递归是树形递归
  3. 若程序输出的第一个数字为2,第二数字为4,剩下还有三个数字,则输入的k()。
    A. 最小值是60,最大值是65
    B. 最小值是65,最大值是70
    C. 最小值是70,最大值是75
    D. 最小值是75,最大值是80
  4. 如果使得输出序列出现7,则输入k最少需要()。
    A. 343
    B. 874
    C. 2170
    D. 5040

三、完善程序

单选题,每小题3分,共计30分。

第1题

有一个用户,在连续的n天里,都会收到积分,也会消费积分。积分在获得后的m天内有效(m为一个给定的整数),过期失效。在第i天,用户将会获得$p_i$分,他需要消费$c_i$分。若积分不足,则用掉全部积分后用其他方式消费。消费积分时,先用最早的。当天获取的积分可以当天消费。请计算这个用户一共消费了多少积分。

const int max_size = 100000;
int queue[max_size];
int head = 0;
int tail = 0;

int main() {
    int n, m;
    std::cin >> n >> m;
    int sum = 0;
    for (int i = 0; i < n; ++i) {
        int p, c;
        std::cin >> p >> c;
        queue[_(1)_] = p;
        while (_(2)_) {
            if (_(3)_) {
                queue[head] -= c;
                sum += c;
                c = 0;
            } else {
                int amount = _(4)_;
                c -= amount;
                sum += amount;
            }
        }
        if (_(5)_ > m) {
            head++;
        }
        std::cout << sum << "\n";
    }
}
  1. (1)处应填()。
    A. tail
    B. tail + 1
    C. i + head
    D. tail++
  2. (2)处应填()。
    A. head < tail || c > 0
    B. head < tail || p > 0
    C. head < tail && c > 0
    D. head < tail && p > 0
  3. (3)处应填()。
    A. queue[head] > c
    B. queue[tail] > c
    C. queue[head + 1] > c
    D. queue[tail - 1] > c
  4. (4)处应填()。
    A. queue[head++]
    B. queue[head]
    C. queue[tail--]
    D. queue[tail]
  5. (5)处应填()。
    A. head - tail
    B. tail - head
    C. tail + head
    D. i - head + 1

第2题

给定一个1到n的排列$p_1, p_2, ..., p_n$。请统计排列中所有长度大于等于2的连续子序列的次大数之和。定义$max_2(a_i, a_{i+1}, ..., a_j)$表示从$a_i$开始到$a_j$结束的连续子序列中,排名第二大的数,这个数就是一个连续子序列的次大数之和。题目就是要求:$\sum_{1 \leq i < j \leq n} max_2(a_i, a_{i+1}, ..., a_j)$。solve用于解决这个问题。

int q[maxn];
int prev[maxn];
int next[maxn];

long long solve(int n, int p[]) {
    for (int i = 1; i <= n; ++i) {
        _(1)_;
    }
    p[0] = q[0] = prev[0] = 0;
    p[n + 1] = q[n + 1] = next[n + 1] = n + 1;
    for (int i = 1; i <= n; ++i) {
        int num = _(2)_;
        int prev_num = p[i - 1];
        int next_num = p[i + 1];
        prev[num] = _(3)_;
        next[num] = _(4)_;
    }
    long long sum = 0;
    for (int num = 1; num <= n; ++num) {
        int prev_num = prev[num];
        int prev_prev_num = prev[prev_num];
        int next_num = next[num];
        int next_next_num = next[next_num];
        sum += (long long)num * (q[num] - q[prev_num]) * _(5)_;
        sum += (long long)num * (q[next_num] - q[num]) * _(6)_;
        _(7)_ = prev_num;
        _(8)_ = next_num;
    }
    return sum;
}
  1. (1)处应填()。
    A. $q[p[i]] = i$
    B. $q[i] = p[i]$
    C. $q[i] = i$
    D. $q[p[i]] = p[i]$
  2. (2)(3)(4)处应填()。
    A. p[i],prev_num,next_num
    B. q[i],next_num,prev_num
    C. p[i],next_num,prev_num
    D. q[i],prev_num,next_num
  3. (5)处应填()。
    A. (q[prev_num] - q[prev_prev_num])
    B. (q[next_next_num] - q[prev_num])
    C. (q[next_num] - q[prev_prev_num])
    D. (q[next_next_num] - q[next_num])
  4. (6)处应填()。
    A. (q[prev_num] - q[prev_prev_num])
    B. (q[next_next_num] - q[prev_num])
    C. (q[next_num] - q[prev_prev_num])
    D. (q[next_next_num] - q[next_num])
  5. (7)(8)处应填()。
    A. prev[prev_num],next[next_num]
    B. prev[next_num],next[prev_num]
    C. next[prev_num],prev[next_num]
    D. next[next_num],prev[prev_num]