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

A - Over Budget

【题目来源】

AtCoder:A - Over Budget

【题目描述】

Takahashi is a manager in charge of \(N\) projects. Each project has already been allocated a budget, but during the end-of-term review, it was discovered that some projects had been allocated too much budget.
高桥是负责 \(N\) 个项目的经理。每个项目都已分配了预算,但在期末审查时发现,部分项目被分配了过多的预算。

The \(i\)-th project \((1 \leq i \leq N)\) has been allocated a budget of \(A_i\) ten-thousand yen, and the appropriate budget amount is \(B_i\) ten-thousand yen. When \(A_i > B_i\), that project is over budget, and \(A_i - B_i\) ten-thousand yen must be returned. When \(A_i \leq B_i\), that project is not over budget, and no return is necessary.
\(i\) 个项目(\(1 ≤ i ≤ N\))已被分配了 \(A_i\) 万日元的预算,而适当的预算金额是 \(B_i\) 万日元。当 \(A_i > B_i\) 时,该项目超出预算,必须返还 \(A_i - B_i\)

Find the number of projects that are over budget and the total amount of money (in ten-thousand yen) that needs to be returned.
求超出预算的项目数量以及需要返还的总金额(以万日元计)。

【输入】

The input is given from standard input in the following format:

\(N\)
\(A_1\) \(B_1\)
\(A_2\) \(B_2\)
\(\vdots\)
\(A_N\) \(B_N\)

The first line gives the number of projects \(N\). The \(i\)-th line \((1 \leq i \leq N)\) of the following \(N\) lines gives the allocated budget \(A_i\) and the appropriate budget amount \(B_i\) for the \(i\)-th project, separated by a space.

【输出】

Output the number of projects that are over budget and the total amount of money (in ten-thousand yen) that needs to be returned, in this order, separated by a space, on a single line as integers.

【输入样例】

3
100 80
50 50
30 60

【输出样例】

1 20

【解题思路】

image

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200005;
int n, cnt, ans;  // n: 数据对数量,cnt: 满足条件的对数,ans: 差值总和
int a[N], b[N];  // a: 第一个数组,b: 第二个数组

signed main()
{
    cin >> n;  // 读入数据对数量
    
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i] >> b[i];  // 读入每个数据对
    }
    
    for (int i = 1; i <= n; i++)
    {
        if (a[i] > b[i])  // 如果a[i]大于b[i]
        {
            cnt++;  // 计数加1
            ans += a[i] - b[i];  // 累加差值
        }
    }
    
    cout << cnt << " " << ans << endl;  // 输出满足条件的对数和差值总和
    return 0;
}

【运行结果】

3
100 80
50 50
30 60
1 20

B - Exam Preparation

【题目来源】

AtCoder:B - Exam Preparation

【题目描述】

Takahashi has to take exams in \(N\) subjects. For each subject \(i\) (\(1 \leq i \leq N\)), he can currently score \(A_i\) points with his present ability. Takahashi needs to score at least the passing mark \(T\) in every subject.
高桥需要参加 \(N\) 门科目的考试。对于每门科目 \(i\)\(1 ≤ i ≤ N\)),以他目前的能力可以取得 \(A_i\) 分。高桥需要在每门科目中至少达到及格分数 \(T\)

By studying additionally, Takahashi can raise his score in each subject. To raise the score in subject \(i\) by \(1\) point, \(C_i\) hours of study are required. That is, to raise the score in subject \(i\) by \(k\) points, \(k \times C_i\) hours of study are required. Note that he cannot lower his score.
通过额外学习,高桥可以提高每门科目的分数。要将科目 \(i\) 的分数提高 \(1\) 分,需要 \(C_i\) 小时的学习时间。也就是说,要将科目 \(i\) 的分数提高 \(k\) 分,需要 \(k × C_i\) 小时的学习时间。注意,他不能降低自己的分数。

For subjects where his current score is already \(T\) or higher, no additional study is needed, and the study time for that subject is \(0\).
对于当前分数已经达到 \(T\) 分或更高的科目,不需要额外学习,该科目的学习时间为 \(0\)

Find the minimum total study time required for Takahashi to bring his score in every subject to \(T\) or higher.
求高桥将每门科目的分数提高到 \(T\) 分或更高所需的最少总学习时间。

【输入】

\(N\) \(T\)
\(A_1\) \(C_1\)
\(A_2\) \(C_2\)
\(\vdots\)
\(A_N\) \(C_N\)

  • The first line contains an integer \(N\) representing the number of subjects and an integer \(T\) representing the passing mark, separated by a space.
  • The \((1 + i)\)-th line (\(1 \leq i \leq N\)) contains the current score \(A_i\) of the \(i\)-th subject and the study time \(C_i\) required to raise that subject's score by \(1\) point, separated by a space.

【输出】

Print in one line the minimum total study time required to bring the scores of all subjects to at least the passing mark \(T\).

【输入样例】

3 60
50 3
70 2
40 5

【输出样例】

130

【解题思路】

image

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 100005;
int n, t, ans;  // n: 数据数量,t: 阈值,ans: 总结果

signed main()
{
    cin >> n >> t;  // 读入数据数量和阈值
    
    for (int i = 1; i <= n; i++)
    {
        int a, c;
        cin >> a >> c;  // 读入a值和系数c
        
        if (a < t)  // 如果a值小于阈值t
        {
            ans += (t - a) * c;  // 计算差值并乘以系数c,累加到结果
        }
    }
    
    cout << ans << endl;  // 输出结果
    return 0;
}

【运行结果】

3 60
50 3
70 2
40 5
130

C - Choosing Souvenirs

【题目来源】

AtCoder:C - Choosing Souvenirs

【题目描述】

Takahashi has come to a souvenir shop to buy souvenirs from his trip. The shop has \(N\) sweets lined up, each with a set price and deliciousness.
高桥来到一家纪念品商店,想为他的旅行购买纪念品。商店里有 \(N\) 种糖果排成一列,每种都有定价和美味度。

The sweets are numbered from \(1\) to \(N\). Sweet \(i\) has a price of \(P_i\) yen and a deliciousness of \(S_i\).
糖果编号从 \(1\)\(N\)。糖果 \(i\) 的价格为 \(P_i\) 日元,美味度为 \(S_i\)

Takahashi wants to choose exactly \(1\) sweet as a souvenir for his friend Aoki, satisfying all of the following conditions:
高桥想恰好选择 \(1\) 种糖果作为送给朋友青木的纪念品,并满足以下所有条件:

  • The price is at least \(L\) yen and at most \(R\) yen.
    价格至少为 \(L\) 日元,至多为 \(R\) 日元。
  • The deliciousness is at least \(T\).
    美味度至少为 \(T\)

If there exists at least one sweet satisfying the conditions, he will choose exactly \(1\) sweet from among them according to the following priorities:
如果存在至少一种满足条件的糖果,他将根据以下优先级从中恰好选择 \(1\) 种糖果:

  • Prefer the one with the lowest price (smallest \(P_i\)).
    优先选择价格最低的(\(P_i\) 最小)。
  • If there are multiple sweets with the same price, prefer the one with the highest deliciousness (largest \(S_i\)).
    如果有多种糖果价格相同,则优先选择美味度最高的(\(S_i\) 最大)。
  • If there are multiple sweets with the same price and the same deliciousness, prefer the one with the smallest number.
    如果有多种糖果价格相同且美味度相同,则优先选择编号最小的。

Since the sweet numbers from \(1\) to \(N\) are all distinct, the sweet chosen by these priorities is uniquely determined. Output the number of the chosen sweet.
如果有多种糖果价格相同且美味度相同,则优先选择编号最小的。

If no sweet satisfies the conditions, output -1.
如果没有糖果满足条件,则输出 -1

【输入】

\(N\) \(L\) \(R\) \(T\)
\(P_1\) \(S_1\)
\(P_2\) \(S_2\)
\(\vdots\)
\(P_N\) \(S_N\)

  • The first line contains the number of sweets \(N\), the lower bound of price \(L\), the upper bound of price \(R\), and the lower bound of deliciousness \(T\), separated by spaces.
  • In the following \(N\) lines, the \(i\)-th line (\(1 \leq i \leq N\)) contains the price \(P_i\) and deliciousness \(S_i\) of sweet \(i\), separated by spaces.

【输出】

If there exists a sweet satisfying the conditions, output the number of the sweet chosen according to the above priorities. If no such sweet exists, output -1.

【输入样例】

5 100 500 3
150 5
200 8
50 10
150 4
600 9

【输出样例】

1

【解题思路】

image

【代码详解】

#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
int n, l, r, t, cur;  // n: 总人数,l: p下限,r: p上限,t: s下限,cur: 合格人数
struct Node
{
    int idx, p, s;  // idx: 原始编号,p: 第一个值,s: 第二个值
}a[N];

// 自定义排序规则
bool cmp(Node x, Node y)
{
    if (x.p != y.p)  // 优先按p升序
    {
        return x.p < y.p;
    }
    else if (x.s != y.s)  // p相同时按s降序
    {
        return x.s > y.s;
    }
    else  // p和s都相同时按原始编号升序
    {
        return x.idx < y.idx;
    }
}

int main()
{
    cin >> n >> l >> r >> t;  // 读入总人数、p的范围和s的下限
    
    for (int i = 1; i <= n; i++)  // 读入每个人的数据
    {
        int p, s;
        cin >> p >> s;
        
        if (p >= l && p <= r && s >= t)  // 筛选符合条件的记录
        {
            a[++cur] = {i, p, s};  // 记录原始编号、p和s
        }
    }
    
    sort(a + 1, a + cur + 1, cmp);  // 对符合条件的记录排序
    
    if (cur == 0)  // 如果没有符合条件的记录
    {
        cout << -1 << endl;
    }
    else
    {
        cout << a[1].idx << endl;  // 输出排序后第一个记录的原始编号
    }
    return 0;
}

【运行结果】

5 100 500 3
150 5
200 8
50 10
150 4
600 9
1

D - The Path of Carrying Luggage

【题目来源】

AtCoder:D - The Path of Carrying Luggage

【题目描述】

Takahashi is a delivery worker who visits \(N\) warehouses arranged in a row, collecting packages in order. The warehouses are numbered \(1, 2, \ldots, N\) from west to east, and warehouse \(i\) contains a package of weight \(A_i\).
高桥是一名送货员,他需要按顺序访问 \(N\) 个排成一列的仓库收集包裹。仓库从西到东编号为 \(1, 2, …, N\),仓库 \(i\) 包含一个重量为 \(A_i\) 的包裹。

Takahashi starts at some warehouse \(s\) (\(1 \leq s \leq N\)) carrying no packages, and visits warehouses sequentially heading east. Each time he visits a warehouse, he picks up the package there and adds it to his load. He keeps all packages he has picked up.
高桥从某个仓库 \(s\)\(1 ≤ s ≤ N\))出发,不携带任何包裹,然后向东依次访问仓库。每次他访问一个仓库,都会拾取那里的包裹并将其加入负载。他会保留所有已拾取的包裹。

Specifically, at each warehouse, he follows these steps:
具体来说,在每个仓库,他遵循以下步骤:

  1. Pick up the package at that warehouse and add it to his load.
    拾取该仓库的包裹并将其加入负载。
  2. Check the total weight of his load (including the package just picked up).
    检查他的负载总重量(包括刚刚拾取的包裹)。
  3. If the total weight is greater than \(K\) (i.e., exceeds \(K\)), Takahashi cannot proceed further and stops at that warehouse.
    如果总重量大于 \(K\)(即超过 \(K\)),高桥无法继续前进,并停在该仓库。
  4. If the total weight is at most \(K\) and the current warehouse is not warehouse \(N\), he moves to the next warehouse (the neighboring warehouse to the east) and returns to step 1.
    如果总重量不超过 \(K\) 且当前仓库不是仓库 \(N\),他移动到下一个仓库(东边的相邻仓库)并返回步骤 \(1\)
  5. If the total weight is at most \(K\) and the current warehouse is warehouse \(N\), there are no more warehouses to the east, so he stops at that warehouse.
    如果总重量不超过 \(K\) 且当前仓库是仓库 \(N\),东边没有更多仓库,因此他停在该仓库。

In other words, when starting from warehouse \(s\), Takahashi visits warehouses \(s, s+1, s+2, \ldots\) in order, and stops at warehouse \(t\) where the cumulative package weight \(A_s + A_{s+1} + \cdots + A_t\) first exceeds \(K\). If he reaches warehouse \(N\) without exceeding \(K\), he stops at warehouse \(N\).
换句话说,当从仓库 \(s\) 开始时,高桥按顺序访问仓库 \(s, s+1, s+2, …\),并停在仓库 \(t\) 处,其中累计包裹重量 \(A_s + A_{s+1} + ⋯ + A_t\) 首次超过 \(K\)。如果他到达仓库 \(N\) 时仍未超过 \(K\),他停在仓库 \(N\)

Define \(f(s)\) as the number of the warehouse where Takahashi stops.
定义 \(f(s)\) 为高桥停止的仓库编号。

Takahashi wants to answer \(Q\) questions. In the \(j\)-th question, integers \(L_j, R_j\) representing a range of starting points are given. Find the value of \(f(L_j) + f(L_j + 1) + \cdots + f(R_j)\).
高桥想要回答 \(Q\) 个问题。在第 \(j\) 个问题中,给定表示起点范围的整数 \(L_j, R_j\)。求 \(f(L_j) + f(L_j+1) + ⋯ + f(R_j)\) 的值。

【输入】

\(N\) \(K\) \(Q\)
\(A_1\) \(A_2\) \(\ldots\) \(A_N\)
\(L_1\) \(R_1\)
\(L_2\) \(R_2\)
\(\vdots\)
\(L_Q\) \(R_Q\)

  • The first line contains the number of warehouses \(N\), the upper limit on total weight \(K\), and the number of questions \(Q\), separated by spaces.
  • The second line contains the weights of packages at each warehouse \(A_1, A_2, \ldots, A_N\), separated by spaces.
  • The following \(Q\) lines each contain the range of starting points \(L_j, R_j\) for each question, separated by spaces.

【输出】

Print \(Q\) lines. On the \(j\)-th line, print the answer to the \(j\)-th question, namely the value of \(f(L_j) + f(L_j + 1) + \cdots + f(R_j)\).

【输入样例】

5 10 3
3 4 2 5 1
1 5
1 3
3 5

【输出样例】

23
13
15

【解题思路】

image

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200005;
int n, k, q;  // n: 数组长度,k: 阈值,q: 查询次数
int a[N], sa[N];  // a: 原数组,sa: 前缀和数组
int f[N], sf[N];  // f: 满足条件的边界数组,sf: f的前缀和数组

signed main()
{
    cin >> n >> k >> q;  // 读入数组长度、阈值和查询次数
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        sa[i] = sa[i - 1] + a[i];  // 计算前缀和
    }
    
    int i = 1, j = 1;  // 双指针,i: 左边界,j: 右边界
    while (i <= n && j <= n)
    {
        if (sa[j] - sa[i - 1] > k)  // 区间和超过k
        {
            f[i] = j;  // 记录以i为左边界,区间和刚好超过k的右边界j
            i++;  // 左边界右移
        }
        else if (j == n)  // 右边界已到数组末尾
        {
            f[i] = j;  // 记录以i为左边界的右边界为n
            i++;  // 左边界右移
        }
        else
        {
            j++;  // 右边界右移
        }
    }
    
    for (int i = 1; i <= n; i++)
    {
        sf[i] = sf[i - 1] + f[i];  // 计算f数组的前缀和
    }
    
    while (q--)  // 处理每个查询
    {
        int l, r;
        cin >> l >> r;
        cout << sf[r] - sf[l - 1] << endl;  // 输出区间和
    }
    
    return 0;
}

【运行结果】

5 10 3
3 4 2 5 1
1 5
23
1 3
13
3 5
15

E - Optimal Route for a Sightseeing Tour

【题目来源】

AtCoder:E - Optimal Route for a Sightseeing Tour

【题目描述】

Takahashi is traveling in a city with \(N\) sightseeing spots. The sightseeing spots are numbered from \(1\) to \(N\), and there are \(M\) bidirectional roads connecting them.
高桥正在一个有 \(N\) 个观光景点的城市旅行。观光景点编号从 \(1\)\(N\),有 \(M\) 条双向道路连接它们。

Each sightseeing spot \(i\) has a positive integer value \(P_i\) called "satisfaction." Takahashi starts from sightseeing spot \(S\), where his hotel is located, and heads to his destination, sightseeing spot \(T\).
每个观光景点 \(i\) 有一个称为"满意度"的正整数值 \(P_i\)。高桥从他酒店所在的观光景点 \(S\) 出发,前往目的地观光景点 \(T\)

Road \(j\) bidirectionally connects sightseeing spots \(U_j\) and \(V_j\), and costs a transportation fee of \(W_j\) regardless of the direction of travel.
道路 \(j\) 双向连接观光景点 \(U_j\)\(V_j\),无论通行方向如何,交通费用均为 \(W_j\)

Takahashi departs from sightseeing spot \(S\) and follows roads sequentially to arrive at sightseeing spot \(T\). He may pass through the same road or the same sightseeing spot any number of times.
高桥从观光景点 \(S\) 出发,依次沿道路前行到达观光景点 \(T\)。他可以多次经过同一条道路或同一个观光景点。

Takahashi's "profit" is defined as follows:
高桥的"利润"定义如下:

  • Consider the set of all sightseeing spots visited along the route, including the starting point \(S\) and the destination \(T\). The profit is the sum of the satisfaction values of each sightseeing spot in this set (counted once each) minus the total transportation fees of all roads traversed along the route.
    考虑沿途访问的所有观光景点的集合,包括起点 \(S\) 和目的地 \(T\)。利润等于该集合中每个观光景点的满意度值之和(每个景点只计一次)减去沿路线行进的所有道路的总交通费用。
  • Even if the same sightseeing spot is visited multiple times, its satisfaction value is added only once.
    即使同一个观光景点被多次访问,其满意度值也只计算一次。
  • If the same road is traversed multiple times, the transportation fee is added for each traversal. Regardless of the direction of travel, each traversal of a road incurs one transportation fee.
    如果同一条道路被多次通行,每次通行都需要加上交通费用。无论通行方向如何,每条道路的每次通行都会产生一次交通费用。

Find the maximum profit when Takahashi travels from sightseeing spot \(S\) to sightseeing spot \(T\).
求高桥从观光景点 \(S\) 到观光景点 \(T\) 旅行时的最大利润。

Note that traversing roads unnecessarily only increases transportation fees without increasing satisfaction, so the maximum profit is always finite. Be aware that the maximum profit may be negative. It is guaranteed that \(T\) is reachable from \(S\).
注意,不必要的通行只会增加交通费用而不会提高满意度,因此最大利润总是有限的。请注意,最大利润可能为负数。保证从 \(S\) 可以到达 \(T\)

【输入】

\(N\) \(M\)
\(P_1\) \(P_2\) \(\ldots\) \(P_N\)
\(S\) \(T\)
\(U_1\) \(V_1\) \(W_1\)
\(U_2\) \(V_2\) \(W_2\)
\(\vdots\)
\(U_M\) \(V_M\) \(W_M\)

  • The first line contains \(N\), the number of sightseeing spots, and \(M\), the number of roads, separated by a space.
  • The second line contains the satisfaction values \(P_1, P_2, \ldots, P_N\) of each sightseeing spot, separated by spaces.
  • The third line contains the starting point \(S\) and the goal point \(T\), separated by a space.
  • The following \(M\) lines provide road information.
  • The \((3 + j)\)-th line contains the sightseeing spots \(U_j\), \(V_j\) connected by the \(j\)-th road and its transportation fee \(W_j\), separated by spaces.

【输出】

Output the maximum profit in a single line. If the maximum profit is negative, output a negative value.

【输入样例】

3 3
10 20 30
1 3
1 2 5
2 3 5
1 3 25

【输出样例】

50

【解题思路】

image

【代码详解】

#include <bits/stdc++.h>
using namespace std;
const int N = 15, M = N * N, INF = -1e9;
int n, m, s, t;  // n: 节点数,m: 边数,s: 起点,t: 终点
int p[N];  // 每个节点的利润
int h[N], e[M], w[M], ne[M], idx;  // 邻接表
int dist[N][N], dp[1 << N][N];  // dist: 距离矩阵(未使用),dp: 状态压缩DP数组

void add(int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

int main()
{
    cin >> n >> m;
    memset(h, -1, sizeof(h));
    // 初始化DP数组
    // for (int mask=0; mask<(1<<n); mask++)
    //     for (int i=0; i<n; i++)
    //         dp[mask][i] = INF;
    memset(dp, -0x3f, sizeof(dp));  // 初始化为极小值
    
    for (int i = 1; i <= n; i++)
    {
        cin >> p[i];  // 读入每个节点的利润
    }
    cin >> s >> t;  // 读入起点和终点
    // int s0=s-1, t0=t-1;  // 这行被注释掉了
    
    for (int i = 1; i <= m; i++)
    {
        int u, v, w;
        cin >> u >> v >> w;
        add(u, v, w), add(v, u, w);  // 添加无向边
    }
    
    int start_mask = 1 << (s - 1);  // 初始状态掩码,只有起点被访问
    dp[start_mask][s] = p[s];  // 初始状态:在起点s,获得起点利润
    
    bool updated = true;
    while (updated)  // 类似SPFA的更新过程
    {
        updated = false;
        for (int mask = 1; mask < (1 << n); mask++)  // 遍历所有状态掩码
        {
            for (int u = 1; u <= n; u++)  // 遍历所有当前节点
            {
                if (dp[mask][u] == -0x3f3f3f3f)  // 当前状态不可达
                {
                    continue;
                }
                for (int i = h[u]; i != -1; i = ne[i])  // 遍历u的所有邻接点
                {
                    int v = e[i];
                    int new_mask = mask | (1 << (v - 1));  // 新状态掩码,加入节点v
                    int new_profit = dp[mask][u] - w[i];  // 新利润 = 当前利润 - 边权
                    
                    if (!(mask & (1 << (v - 1))))  // 如果v是第一次访问
                    {
                        new_profit += p[v];  // 加上v的利润
                    }
                    
                    if (new_profit > dp[new_mask][v])  // 如果可以获得更多利润
                    {
                        dp[new_mask][v] = new_profit;
                        updated = true;  // 标记有更新
                    }
                }
            }
        }
    }
    
    int ans = INF;
    for (int mask = 1; mask < (1 << n); mask++)  // 遍历所有状态
    {
        if (mask & (1 << (t - 1)))  // 如果状态中包含终点t
        {
            ans = max(ans, dp[mask][t]);  // 更新最大利润
        }
    }
    cout << ans << endl;
    return 0;
}

【运行结果】

3 3
10 20 30
1 3
1 2 5
2 3 5
1 3 25
50
posted @ 2026-03-11 10:03  团爸讲算法  阅读(1)  评论(0)    收藏  举报