AtCoder Weekday Contest 0027 Beta题解(AWC 0027 Beta A-E)

A - Passing Criteria

【题目来源】

AtCoder:A - Passing Criteria

【题目描述】

Takahashi has been asked by his school teacher to compile the grading results of a test.
高桥被学校老师要求整理一次考试的评分结果。

For this test, a reference score of \(S\) points and a tolerance of \(T\) points are set. If the absolute difference between a student's score \(A_i\) and the reference score \(S\) is at most \(T\), that is, if \(|A_i - S| \leq T\), then the student is judged as "passing."
对于这次考试,设定了参考分数 \(S\) 分和容差 \(T\) 分。如果学生的分数 \(A_i\) 与参考分数 \(S\) 的绝对差不超过 \(T\),即如果 \(|A_i - S| \leq T\),则该学生被判定为"通过"。

\(N\) students took the test, and the score of the \(i\)-th student \((1 \leq i \leq N)\) was \(A_i\) points.
\(N\) 名学生参加了考试,第 \(i\) 名学生(\(1 \leq i \leq N\))的分数为 \(A_i\) 分。

Find the number of students who passed.
求通过考试的学生人数。

【输入】

\(N\) \(S\) \(T\)
\(A_1\) \(A_2\) \(\ldots\) \(A_N\)

  • The first line contains \(N\) representing the number of students, \(S\) representing the reference score, and \(T\) representing the tolerance, separated by spaces.
  • The second line contains \(A_1, A_2, \ldots, A_N\) representing each student's score, separated by spaces.
  • \(A_i\) represents the score of the \(i\)-th student.

【输出】

Print the number of students who passed in one line.

【输入样例】

5 60 10
55 70 62 45 58

【输出样例】

4

【代码详解】

#include <bits/stdc++.h>  // 包含所有标准库头文件
using namespace std;       // 使用标准命名空间

int n, s, t, cnt;  // 定义变量:n(总数量), s(中心点), t(阈值), cnt(计数器)

int main()  // 主函数入口
{
    // 输入三个整数:n(总数量), s(中心点), t(允许的最大距离)
    cin >> n >> s >> t;
    
    // 循环n次,读取每个点
    for (int i = 1; i <= n; i++)
    {
        int x;  // 定义临时变量x,存储当前点的值
        cin >> x;  // 读取当前点的值
        
        // 判断当前点x与中心点s的距离是否在阈值t以内
        // abs(x-s)计算两点之间的绝对距离
        if (abs(x - s) <= t)
        {
            cnt++;  // 如果距离满足条件,计数器加1
        }
    }
    
    cout << cnt << endl;  // 输出满足条件的点的数量
    return 0;  // 程序正常结束
}

【运行结果】

5 60 10
55 70 62 45 58
4

B - Election of the Class President

【题目来源】

AtCoder:B - Election of the Class President

【题目描述】

Takahashi is a school teacher in charge of selecting the class representative. There are \(N\) students in the class, and each student is assigned an attendance number from \(1\) to \(N\). The leadership score of student \(i\) is \(A_i\).
高桥是一名负责选拔班长的学校老师。班上有 \(N\) 名学生,每名学生被分配了从 \(1\)\(N\) 的出勤编号。学生 \(i\) 的领导力分数为 \(A_i\)

Currently, the student with attendance number \(1\) is provisionally registered as the class representative. Takahashi will change the representative if there exists a student other than the current representative whose leadership score is strictly greater than that of the current representative.
目前,出勤编号为 \(1\) 的学生被暂定为班长。如果存在一名学生(非现任班长),其领导力分数严格大于现任班长的领导力分数,高桥将更换班长。

Specifically, Takahashi follows the rules below:
具体来说,高桥遵循以下规则:

  1. If there exists one or more students whose leadership score is strictly greater than that of the current representative (the student with attendance number \(1\)), the student with the highest leadership score among them is appointed as the new representative. If there are multiple students with the highest leadership score, the one with the smallest attendance number is chosen.
    如果存在一名或多名学生,其领导力分数严格大于现任班长(出勤编号为 \(1\) 的学生)的领导力分数,则其中领导力分数最高的学生被任命为新班长。如果有多个学生具有相同的最高领导力分数,则选择出勤编号最小的学生。
  2. If there is no student whose leadership score is strictly greater than that of the current representative, the representative is not changed.
    如果没有学生的领导力分数严格大于现任班长的领导力分数,则不更换班长。

If Takahashi changed the representative, output the attendance number of the new representative. If no change was made, output \(-1\).
如果高桥更换了班长,输出新班长的出勤编号。如果未作更换,输出 \(-1\)

【输入】

\(N\)
\(A_1\) \(A_2\) \(\ldots\) \(A_N\)

  • The first line contains an integer \(N\), representing the number of students.
  • The second line contains integers \(A_1, A_2, \ldots, A_N\) separated by spaces, representing the leadership scores of each student. \(A_i\) is the leadership score of the student with attendance number \(i\).

【输出】

If the representative was changed, output the attendance number of the new representative. If no change was made, output \(-1\) on a single line.

【输入样例】

5
3 7 5 7 2

【输出样例】

2

【代码详解】

#include <bits/stdc++.h>  // 包含所有标准库头文件
using namespace std;       // 使用标准命名空间

int n, x;  // 定义变量:n(数字总数), x(临时变量,存储当前数字)

int main()  // 主函数入口
{
    // 输入数字总数n和第一个数字x
    cin >> n >> x;
    
    // 初始化最大值为第一个数字,最大值的位置为1
    int maxn = x;   // maxn: 记录当前最大值
    int maxid = 1;  // maxid: 记录最大值所在的位置(索引)
    
    // 从第2个数字开始遍历到第n个数字
    for (int i = 2; i <= n; i++)
    {
        int x;  // 声明新的局部变量x,与全局变量x不同
        cin >> x;  // 输入第i个数字
        
        // 如果当前数字大于已记录的最大值
        if (x > maxn)
        {
            maxid = i;  // 更新最大值的位置为当前索引i
            maxn = x;   // 更新最大值为当前数字x
        }
    }
    
    // 判断最大值是否出现在第一个位置
    if (maxid == 1)
    {
        cout << -1 << endl;  // 如果是,输出-1
    }
    else
    {
        cout << maxid << endl;  // 如果不是,输出最大值的位置
    }
    
    return 0;  // 程序正常结束
}

【运行结果】

5
3 7 5 7 2
2

C - Building a Wireless Network

【题目来源】

AtCoder:C - Building a Wireless Network

【题目描述】

Takahashi is trying to build a wireless network using \(N\) base stations. The base stations are numbered from \(1\) to \(N\). The base stations are placed on a number line, and base station \(i\) is located at coordinate \(X_i\). No two base stations are placed at the same coordinate.
高桥正试图使用 \(N\) 个基站构建一个无线网络。基站编号从 \(1\)\(N\)。基站放置在一条数轴上,基站 \(i\) 位于坐标 \(X_i\) 处。没有两个基站位于同一坐标。

Each base station is equipped with a wireless device that has the same communication range \(K\), where \(K\) is a non-negative integer. Two base stations \(i\) and \(j\) can communicate directly if the distance between them is at most \(K\), that is, \(|X_i - X_j| \leq K\).
每个基站配备了一个具有相同通信范围 \(K\) 的无线设备,其中 \(K\) 是一个非负整数。如果两个基站 \(i\)\(j\) 之间的距离不超过 \(K\),即 \(|X_i - X_j| \leq K\),则它们可以直接通信。

Takahashi wants to build a network such that any two distinct base stations can communicate, either directly or by relaying through one or more other base stations. More precisely, for any two distinct base stations \(s\) and \(t\), there should exist a sequence of base stations \(s = v_1, v_2, \ldots, v_m = t\) (\(m \geq 2\)) such that consecutive stations \(v_k\) and \(v_{k+1}\) (\(1 \leq k \leq m-1\)) can each communicate directly. Note that when \(N = 1\), there is only one base station, so this condition is always satisfied regardless of the value of \(K\).
高桥希望构建一个网络,使得任意两个不同的基站可以直接通信,或通过一个或多个其他基站中继通信。更准确地说,对于任意两个不同的基站 \(s\)\(t\),应该存在一个基站序列 \(s = v_1, v_2, \ldots, v_m = t\)\(m \geq 2\)),使得连续的基站 \(v_k\)\(v_{k+1}\)\(1 \leq k \leq m-1\))都可以直接通信。注意,当 \(N = 1\) 时,只有一个基站,因此无论 \(K\) 取何值,此条件始终满足。

To reduce the cost of the wireless devices, Takahashi wants to make the communication range \(K\) as small as possible.
为了降低无线设备的成本,高桥希望使通信范围 \(K\) 尽可能小。

Since all base station coordinates are integers, the minimum value of \(K\) that satisfies the condition is guaranteed to be a non-negative integer. Find this minimum value.
由于所有基站坐标都是整数,满足条件的最小 \(K\) 值保证是一个非负整数。求此最小值。

【输入】

\(N\)
\(X_1\) \(X_2\) \(\ldots\) \(X_N\)

  • The first line contains an integer \(N\), representing the number of base stations.
  • The second line contains \(N\) integers \(X_1, X_2, \ldots, X_N\) separated by spaces, representing the coordinates of each base station.

【输出】

Print in one line the minimum value of \(K\) required for all base stations to be able to communicate with each other.

【输入样例】

3
1 5 3

【输出样例】

2

【代码详解】

#include <bits/stdc++.h>  // 包含所有标准库头文件
using namespace std;       // 使用标准命名空间

const int N = 200005;  // 定义常量N,表示数组最大容量
int n, x[N];           // n: 数字个数, x[]: 存储数字的数组

// 检查函数:判断给定的最大差值mid是否可行
bool check(int mid)
{
    // 调试输出,可以取消注释查看mid的值
    // cout << "mid " << mid << endl;
    
    // 遍历数组,检查相邻元素的差值
    for (int i = 1; i < n; i++)
    {
        // 如果相邻两个数的差的绝对值大于mid,说明mid不可行
        if (abs(x[i] - x[i + 1]) > mid)
        {
            return false;  // 返回false,当前mid值太小
        }
    }
    return true;  // 所有相邻元素差值都不超过mid,返回true
}

int main()  // 主函数入口
{
    cin >> n;  // 输入数字个数n
    
    // 读取n个数字
    for (int i = 1; i <= n; i++)
    {
        cin >> x[i];  // 读取第i个数字
    }
    
    // 对数组进行排序(从小到大)
    sort(x + 1, x + n + 1);
    
    // 二分查找
    int l = 0;      // 左边界,最小可能的最大差值
    int r = 1e9;    // 右边界,最大可能的最大差值(1e9是10^9)
    
    // 二分查找模板:寻找满足条件的最小值
    while (l < r)
    {
        int mid = (l + r) / 2;  // 取中间值
        
        // 检查mid是否可行
        if (check(mid))
        {
            r = mid;  // 如果mid可行,尝试更小的值
        }
        else
        {
            l = mid + 1;  // 如果mid不可行,需要更大的值
        }
    }
    
    cout << l << endl;  // 输出结果,此时l=r,是满足条件的最小值
    return 0;           // 程序正常结束
}

【运行结果】

3
1 5 3
2

D - Part-Time Job Shift Assignment

【题目来源】

AtCoder:D - Part-Time Job Shift Assignment

【题目描述】

Takahashi is in charge of shift management as the store manager at his part-time workplace.
高桥作为兼职店的店长,负责排班管理。

He needs to create a shift schedule for the upcoming \(N\) business days. Each business day is numbered \(1, 2, \ldots, N\), and business day \(i\) \((1 \leq i \leq N)\) has a required skill level \(H_i\) and an expected sales amount \(S_i\).
他需要为接下来的 \(N\) 个营业日创建一份排班表。每个营业日编号为 \(1, 2, \ldots, N\),营业日 \(i\)\(1 \leq i \leq N\))有一个要求的技能水平 \(H_i\) 和预期销售额 \(S_i\)

Takahashi's store has \(M\) part-time workers, and each worker \(j\) \((1 \leq j \leq M)\) has a skill level \(P_j\). To assign worker \(j\) to business day \(i\), the condition \(H_i \leq P_j\) must be satisfied. In other words, only workers whose skill level is at least the required skill level for that day can be assigned to it.
高桥的店里有 \(M\) 名兼职员工,每位员工 \(j\)\(1 \leq j \leq M\))有一个技能水平 \(P_j\)。要将员工 \(j\) 分配到营业日 \(i\),必须满足条件 \(H_i \leq P_j\)。换句话说,只有技能水平不低于该营业日所需技能水平的员工才能被分配到该日。

Takahashi wants to assign all \(M\) part-time workers to distinct business days. Since \(M \leq N\), there may be business days with no worker assigned. Specifically, the assignment must satisfy all of the following conditions:
高桥希望将所有 \(M\) 名兼职员工分配到不同的营业日。由于 \(M \leq N\),可能会有一些营业日没有分配员工。具体来说,分配必须满足以下所有条件:

  • Each worker is assigned to exactly \(1\) business day. That is, all \(M\) workers are assigned to some business day, and no one is left unassigned.
    每名员工被分配到恰好 \(1\) 个营业日。也就是说,所有 \(M\) 名员工都被分配到某个营业日,没有人被遗漏。
  • At most \(1\) worker is assigned to each business day. That is, no business day has \(2\) or more workers assigned to it.
    每个营业日最多分配 \(1\) 名员工。也就是说,没有营业日被分配 \(2\) 名或更多员工。
  • If worker \(j\) is assigned to business day \(i\), then \(H_i \leq P_j\) must hold.
    如果员工 \(j\) 被分配到营业日 \(i\),则必须满足 \(H_i \leq P_j\)

The expected sales are obtained only for business days that have a worker assigned. That is, if the set of business days with assigned workers in a certain assignment is \(T\), then the total sales for that assignment is \(\displaystyle\sum_{i \in T} S_i\).
只有分配了员工的营业日才能获得预期销售额。也就是说,如果在某个分配中,有员工分配的营业日集合为 \(T\),那么该分配的总销售额\(\displaystyle\sum_{i \in T} S_i\)

Determine whether it is possible to assign all workers in a way that satisfies the above conditions. If it is possible, find the maximum total sales among all valid assignments. If it is impossible, output \(-1\).
判断是否可能以符合上述条件的方式分配所有员工。如果可能,求所有有效分配中的最大总销售额。如果不可能,输出 \(-1\)

【输入】

\(N\) \(M\)
\(H_1\) \(S_1\)
\(H_2\) \(S_2\)
\(\vdots\)
\(H_N\) \(S_N\)
\(P_1\) \(P_2\) \(\ldots\) \(P_M\)

  • The first line contains an integer \(N\) representing the number of business days and an integer \(M\) representing the number of part-time workers, separated by a space.
  • The following \(N\) lines, where line \(i\) \((1 \leq i \leq N)\), contain the required skill level \(H_i\) and expected sales \(S_i\) for business day \(i\), separated by a space.
  • The last line contains the skill levels \(P_1, P_2, \ldots, P_M\) of each part-time worker, separated by spaces.

【输出】

If it is possible to assign all workers to distinct business days satisfying the conditions, output the maximum total sales in one line. If it is impossible, output \(-1\).

【输入样例】

5 3
3 100
5 200
2 150
4 80
1 50
4 3 2

【输出样例】

330

【解题思路】

image

【代码详解】

// 包含所有标准库
#include <bits/stdc++.h>
using namespace std;

// 定义长整型别名
#define int long long

// 定义数组最大容量
const int N = 200005;

// 全局变量声明
int n, m;  // n: 营业日数量, m: 员工数量

// 营业日结构体
struct Node
{
    int h, s;  // h: 要求的技能水平, s: 预期销售额
}a[N];  // 营业日数组

int p[N];  // 员工技能水平数组
int ans;   // 总销售额
bool vis[N];  // 标记数组(代码中未使用)

// 比较函数,用于排序营业日
bool cmp(Node x, Node y)
{
    // 首先按技能要求h升序排序
    if (x.h != y.h) 
    {
        return x.h < y.h;
    }
    
    // 当h相同时,按销售额s升序排序
    return x.s < y.s;    
}

// 主函数
signed main()
{
    // 读入营业日数量和员工数量
    cin >> n >> m;
    
    // 读入每个营业日的技能要求和预期销售额
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i].h >> a[i].s;
    }

    // 对营业日数组进行排序
    // 排序规则:先按h升序,h相同时按s升序
    sort(a + 1, a + n + 1, cmp);
    
    // 读入每个员工的技能水平
    for (int i = 1; i <= m; i++)
    {
        cin >> p[i];
    }

    // 对员工技能水平数组进行升序排序
    sort(p + 1, p + m + 1);
    
    // 使用multiset存储可用的营业日销售额
    // greater<int> 表示降序排列,即最大的元素在begin()位置
    multiset<int, greater<int>> available;
    
    // 营业日指针,用于遍历排序后的营业日数组
    int j = 1;  
    
    // 遍历所有员工(从技能最低的开始)
    for (int i = 1; i <= m; i++)
    {
        // 将所有技能要求不超过当前员工技能的营业日加入available集合
        // 条件:a[j].h <= p[i],即营业日j的技能要求 <= 员工i的技能水平
        while (j <= n && a[j].h <= p[i])
        {
            // 将营业日的销售额插入multiset
            available.insert(a[j].s);
            j++;  // 指针后移,处理下一个营业日
        }
        
        // 如果没有可用的营业日
        if (available.empty())
        {
            // 输出-1表示无法分配所有员工
            cout << -1 << endl;
            return 0;  // 提前结束程序
        }
        
        // 从可用的营业日中选择销售额最大的
        auto it = available.begin();  // 获取最大销售额的迭代器
        ans += *it;                   // 累加到总销售额
        available.erase(it);          // 从集合中删除已分配的营业日
    }
    
    // 输出最大总销售额
    cout << ans << endl;
    
    return 0;  // 程序正常结束
}
#include <bits/stdc++.h>  // 包含所有标准库头文件
using namespace std;       // 使用标准命名空间
#define int long long      // 将int定义为long long,防止溢出

const int N = 200005;      // 定义数组大小常量

int n, m;                  // n:人数, m:任务数量

// 定义人的结构体
struct Node
{
    int h;  // 身高
    int s;  // 分数
} a[N];     // 人的数组

int p[N];    // 任务数组,存储每个任务的身高限制
int ans;     // 最终答案,记录最大总分
bool vis[N]; // 标记数组,但代码中未使用
priority_queue<int> pq;  // 最大堆优先队列,用于存储可选择的分数

// 自定义比较函数,用于排序
bool cmp(Node x, Node y)
{
    // 第一优先级:按身高从小到大排序
    if (x.h != y.h)
    {
        return x.h < y.h;
    }
    // 第二优先级:身高相同,按分数从小到大排序
    return x.s < y.s;
}

signed main()  // 主函数入口,使用signed替代int(因为定义了int为long long)
{
    cin >> n >> m;  // 输入人数n和任务数量m
    
    // 输入每个人的信息
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i].h >> a[i].s;  // 输入身高和分数
    }
    
    // 将人按身高排序,身高相同按分数排序
    sort(a + 1, a + n + 1, cmp);
    
    // 输入每个任务的身高限制
    for (int i = 1; i <= m; i++)
    {
        cin >> p[i];  // 输入第i个任务的身高限制
    }
    
    // 将任务按身高限制排序
    sort(p + 1, p + m + 1);
    
    int j = 1;  // 指针j,指向当前考虑的人的索引(从1开始)
    
    // 遍历所有任务
    for (int i = 1; i <= m; i++)
    {
        // 将所有身高不超过当前任务限制p[i]的人加入优先队列
        while (j <= n && a[j].h <= p[i])
        {
            pq.push(a[j].s);  // 将人的分数加入优先队列
            j++;              // 移动到下一个人
        }
        
        // 如果优先队列为空,说明没有满足当前任务条件的人
        if (pq.empty())
        {
            cout << -1 << endl;  // 输出-1表示无法完成
            return 0;            // 直接结束程序
        }
        
        // 从优先队列中取出分数最高的人
        ans += pq.top();  // 累加分数
        pq.pop();         // 将该人从队列中移除
    }
    
    cout << ans << endl;  // 输出最大总分
    return 0;             // 程序正常结束
}

【运行结果】

5 3
3 100
5 200
2 150
4 80
1 50
4 3 2
330

E - Selection of Contiguous Intervals

【题目来源】

AtCoder:E - Selection of Contiguous Intervals

【题目描述】

Takahashi has a sequence of \(N\) integers \(A_1, A_2, \ldots, A_N\).
高桥有一个包含 \(N\) 个整数的序列 \(A_1, A_2, \ldots, A_N\)

Takahashi wants to select one contiguous interval from this sequence. Specifically, he chooses a pair of integers \((l, r)\) (\(1 \leq l \leq r \leq N\)) and extracts the elements from the \(l\)-th to the \(r\)-th.
高桥想从这个序列中选择一个连续区间。具体来说,他选择一对整数 \((l, r)\)\(1 \leq l \leq r \leq N\)),并提取第 \(l\) 到第 \(r\) 个元素。

The score of the chosen interval is defined as follows:
所选区间的得分定义如下:

\(f(l, r) = \sum_{i=l}^{r} A_i + (r - l + 1) \times M\)

That is, the score is the sum of the elements in the interval plus the product of the interval length \((r - l + 1)\) and a positive integer \(M\).
也就是说,得分是区间内元素之和加上区间长度 \((r - l + 1)\) 与一个正整数 \(M\) 的乘积。

Find the number of integer pairs \((l, r)\) (\(1 \leq l \leq r \leq N\)) such that the score is at most \(K\).
求满足得分不超过 \(K\) 的整数对 \((l, r)\)\(1 \leq l \leq r \leq N\))的数量。

【输入】

\(N\) \(M\) \(K\)
\(A_1\) \(A_2\) \(\cdots\) \(A_N\)

  • The first line contains the length of the sequence \(N\), the score coefficient \(M\), and the score upper bound \(K\), separated by spaces.
  • The second line contains the elements of the sequence \(A_1, A_2, \ldots, A_N\), separated by spaces.

【输出】

Print in one line the number of integer pairs \((l, r)\) (\(1 \leq l \leq r \leq N\)) such that the score is at most \(K\).

【输入样例】

5 2 10
1 3 2 4 1

【输出样例】

9

【解题思路】

image

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200005;
int n, m, k;
int a[N], sa[N], tr[N * 2], ans;  // tr数组开2倍大小,因为离散化后最多有2*(n+1)个不同的值
map<int, int> mp;  // 用于存储原值到离散化后索引的映射

// 离散化函数:将原始值映射到1开始的连续整数
vector<int> compress(vector<int> a)
{
    auto b = a;  // 复制一份原始数据
    sort(b.begin(), b.end());  // 排序
    b.erase(unique(b.begin(), b.end()), b.end());  // 去重
    vector<int> res(a.size());  // 创建结果数组,指定大小避免越界
    for (int i = 0; i < a.size(); i++)
    {
        // 使用二分查找获取离散化后的索引(从1开始)
        res[i] = lower_bound(b.begin(), b.end(), a[i]) - b.begin() + 1;
    }
    return res;
}

// 计算x的二进制表示中最低位的1所代表的值
int lowbit(int x)
{
    return x & -x;
}

// 树状数组的更新操作:在位置x增加c
void add(int x, int c, int size)
{
    // 向后更新:更新当前位置及其父节点
    for (int i = x; i <= size; i += lowbit(i))
    {
        tr[i] += c;
    }
}

// 树状数组的查询操作:查询前缀和[1, x]
int query(int x)
{
    int res = 0;
    // 向前查询:累加当前位置及其左子树的和
    for (int i = x; i; i -= lowbit(i))
    {
        res += tr[i];
    }
    return res;
}

signed main()
{
    cin >> n >> m >> k;
    
    // 读取数组并计算前缀和:sa[i] = Σ(A[j] + m) for j=1..i
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        sa[i] = sa[i - 1] + a[i] + m;  // 计算前缀和,每个元素都加上m
    }
    
    // 收集所有需要离散化的值
    vector<int> alls;
    alls.push_back(0);  // 添加sa[0] = 0
    
    // 对于每个前缀和,添加两个值:
    // 1. 前缀和本身sa[i]:用于插入树状数组
    // 2. 前缀和减去k:sa[i]-k:用于查询条件
    for (int i = 0; i <= n; i++)
    {
        alls.push_back(sa[i]);
        alls.push_back(sa[i] - k);
    }
    
    // 离散化处理
    vector<int> compressed = compress(alls);
    
    // 建立映射:原值 -> 离散化后的索引
    for (int i = 0; i < alls.size(); i++)
    {
        mp[alls[i]] = compressed[i];
    }
    
    int sz = compressed.size();  // 离散化后的总大小
    
    // 初始化树状数组,先添加sa[0] = 0
    add(mp[0], 1, sz);
    
    // 遍历每个右端点r(对应区间[?, r])
    for (int r = 1; r <= n; r++)
    {
        // 查询条件:我们需要找到满足 sa[r] - sa[l-1] <= k 的l
        // 等价于:sa[l-1] >= sa[r] - k
        int target = sa[r] - k;  // 查询目标值
        int target_idx = mp[target];  // 目标值的离散化索引
        
        // 计算已添加的元素个数:sa[0]到sa[r-1],共r个
        int total = r;
        
        // 查询小于target的元素个数
        int less_than = query(target_idx - 1);
        
        // 大于等于target的元素个数 = 总数 - 小于target的个数
        int ge_target = total - less_than;
        
        // 累加到答案中
        ans += ge_target;
        
        // 将当前sa[r]添加到树状数组中,供后续查询使用
        add(mp[sa[r]], 1, sz);
    }
    
    cout << ans << endl;
    return 0;
}

【运行结果】

5 2 10
1 3 2 4 1
9
posted @ 2026-03-18 10:10  团爸讲算法  阅读(4)  评论(0)    收藏  举报