Martian148's blog Martian148's blog
首页
  • ICPC 算法笔记
  • ICPC 算法题解
  • 体系结构
  • 高等数学
  • 线性代数
  • 概率论与数理统计
  • 具体数学
  • Martian148的奇思妙想
  • 游记
  • 通识课笔记
关于
  • useful 网站
  • 友情链接
  • 分类
  • 归档

Martian148

一只热爱文科的理科生
首页
  • ICPC 算法笔记
  • ICPC 算法题解
  • 体系结构
  • 高等数学
  • 线性代数
  • 概率论与数理统计
  • 具体数学
  • Martian148的奇思妙想
  • 游记
  • 通识课笔记
关于
  • useful 网站
  • 友情链接
  • 分类
  • 归档
  • codeforses 题解

  • atcoder 题解

    • AtCoder Beginner Contest 344 A-G 题解
    • AtCoder Beginner Contest 345 A-F 题解
    • AtCoder Beginner Contest 346 A-G 题解
    • AtCoder Beginner Contest 347 A-G 题解
    • AtCoder Beginner Contest 353 A-G 题解
      • A - Buildings
        • Solution
        • Code
      • B - AtCoder Amusement Park
        • Solution
        • Code
      • C - Sigma Problem
        • Question
        • Solution
      • D - Another Sigma Problem
        • Question
        • Solution
        • Code
      • E - Yet Another Sigma Problem
        • Question
        • Solution
        • Code
      • F - Tile Distance
        • Question
        • Solution
        • Code
      • G - Merchant Takahashi
        • Question
        • Solution
        • Code
    • AtCoder Beginner Contest 359 A-G 题解
    • AtCoder Beginner Contest 366 A-F 题解
    • AtCoder Beginner Contest 369 A-F 题解
  • XCPC 题解

  • 校训练赛题解

  • 牛客题解

  • 蓝桥杯题解

  • 典题选讲

  • 杂题

  • 算法题解
  • atcoder 题解
chengyiwei
2024-08-02
目录

AtCoder Beginner Contest 353 A-G 题解

AtCoder Beginner Contest 353 (opens new window)

# A - Buildings

# Solution

纯模拟

# Code

#include <bits/stdc++.h>
using namespace std;
int main() {
    int n; cin >> n;
    vector<int> a(n + 1);
    int pos = -1;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 2; i <= n; i++) 
        if (a[i] > a[1]) {
            pos = i;
            break;
        }
    cout << pos << endl;
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# B - AtCoder Amusement Park

# Solution

使用两个指针模拟

# Code

#include <bits/stdc++.h>
using namespace std;
int main() {
    int ans = 0;
    int n, k; cin >> n >> k;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1; i <= n;) {
        int sum = 0;
        int j = i;
        while (j <= n && sum + a[j] <= k) sum += a[j++];
        ans += 1; 
        i = j;
    }
    cout << ans << endl;
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# C - Sigma Problem

# Question

C - Sigma Problem (opens new window)

对于正整数 xxx 和 yyy,定义 f(x,y)f(x,y)f(x,y) 为 (x+y)%109(x+y) \% 10^9(x+y)%109

给定一个长度为 NNN 的序列 A=(A1,A2,⋯,AN)A=(A_1,A_2,\cdots, A_N)A=(A1​,A2​,⋯,AN​) 计算:

∑i=1N−1∑j=i+1Nf(Ai,Aj) \sum\limits_{i=1}^{N-1}\sum\limits_{j=i+1}^{N}f(A_i,A_j) i=1∑N−1​j=i+1∑N​f(Ai​,Aj​)

# Solution

Ai+AjA_i+A_jAi​+Aj​ 的最大值是 2×1092\times 10 ^92×109 所以如果 (Ai+Aj)/109(A_i+A_j)/10^9(Ai​+Aj​)/109 最大为 111

所以对于 (Ai+Aj)%109=(Ai+Aj)−109(A_i+A_j)\% 10^9=(A_i+A_j)-10^9(Ai​+Aj​)%109=(Ai​+Aj​)−109

我们对于每个 AiA_iAi​ 只需要求出有多少 Ai+Aj>109A_i+A_j>10^9Ai​+Aj​>109 对于 AiA_iAi​ 排序后,iii 从小到大枚举,分界点从大变小,可以用双指针来实现

# D - Another Sigma Problem

# Question

定义 f(x,y)f(x,y)f(x,y) 表示把两个十进制接起来

例如 f(2,14)=214f(2,14)=214f(2,14)=214

给定数组 AAA,求:

∑i=1N−1∑j=i+1Nf(Ai,Aj) \sum\limits_{i=1}^{N-1}\sum\limits_{j=i+1}^N f(A_i,A_j) i=1∑N−1​j=i+1∑N​f(Ai​,Aj​)

# Solution

化简 f(Ai,Aj)=Ai×10∣Aj∣+Ajf(A_i,A_j)=A_i\times 10^{|A_j|}+A_jf(Ai​,Aj​)=Ai​×10∣Aj​∣+Aj​

∑i=1N−1∑j=i+1Nf(Ai,Aj)=∑j=2N∑i=1j−1f(Ai,Aj)=∑j=2N∑i=1j−1Ai×10∣Aj∣+Aj=∑j=2N(Aj+10∣Aj∣×∑i=1j−1Ai) \begin{aligned} \sum\limits_{i=1}^{N-1}\sum\limits_{j=i+1}^N f(A_i,A_j) &=\sum\limits_{j=2}^{N}\sum\limits_{i=1}^{j-1}f(A_i,A_j)\\ &=\sum\limits_{j=2}^{N}\sum\limits_{i=1}^{j-1} A_i\times 10^{|A_j|}+A_j\\ &=\sum\limits_{j=2}^N (A_j+10^{|A_j|}\times \sum\limits_{i=1}^{j-1} A_i) \end{aligned} i=1∑N−1​j=i+1∑N​f(Ai​,Aj​)​=j=2∑N​i=1∑j−1​f(Ai​,Aj​)=j=2∑N​i=1∑j−1​Ai​×10∣Aj​∣+Aj​=j=2∑N​(Aj​+10∣Aj​∣×i=1∑j−1​Ai​)​

# Code

#include <bits/stdc++.h>
using namespace std;
int main() {
    int ans = 0;
    int n, k; cin >> n >> k;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1; i <= n;) {
        int sum = 0;
        int j = i;
        while (j <= n && sum + a[j] <= k) sum += a[j++];
        ans += 1; 
        i = j;
    }
    cout << ans << endl;
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# E - Yet Another Sigma Problem

# Question

对于字符串 xxx 和 yyy ,定义 f(x,y)f(x, y)f(x,y) 如下:

  • f(x,y)f(x, y)f(x,y) 是 xxx 和 yyy 的最长公共前缀的长度。

给你一个由小写英文字母组成的 NNN 字符串 (S1,…,SN)(S_1, \ldots, S_N)(S1​,…,SN​) 求:

∑i=1N−1∑j=i+1Nf(Si,Sj) \displaystyle \sum_{i=1}^{N-1}\sum_{j=i+1}^N f(S_i,S_j) i=1∑N−1​j=i+1∑N​f(Si​,Sj​)

# Solution

字典树板子题

# Code

#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
const int maxn = 3e5 + 10;

int cnt;

struct Node {
    int val;
    int son[26];
    Node() {
        val = 0;
        memset (son, 0, sizeof (son));
    }
}tr[maxn];

void insert (string s) {
    int p = 0;
    for (int i = 0; i < s.size(); i++) {
        int u = s[i] - 'a';
        if (!tr[p].son[u]) tr[p].son[u] = ++cnt;
        p = tr[p].son[u];
        tr[p].val += 1;
    }
}

int find_same (string s) {
    int p = 0;
    int res = 0;
    for (int i = 0; i < s.size(); i++) {
        int u = s[i] - 'a';
        if (!tr[p].son[u]) break;
        p = tr[p].son[u];
        res += tr[p].val;
    }
    return res;
}

signed main() {
    // freopen ("E.in", "r", stdin);
    int n; cin >> n;
    ll ans = 0;
    for (int i = 1; i <= n; i++) {
        string s; cin >> s;
        ans += find_same (s);
        insert (s);
    }
    cout << ans << endl;
    return 0;
}
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
44
45
46
47
48
49
50
51

# F - Tile Distance

# Question

F - Tile Distance (opens new window)

坐标平面上有两种类型的瓷砖,大小为 1×11\times 11×1 和大小为 K×KK\times KK×K

交替铺设,穿过一个瓷砖的代价为 111

image.png

问高桥从点 (Sx+0.5,Sy+0.5)(S_x+0.5,S_y+0.5)(Sx​+0.5,Sy​+0.5) 移动到点 (Tx+0.5,Ty+0.5)(T_x+0.5,T_y+0.5)(Tx​+0.5,Ty​+0.5) 的最小代价

# Solution

显然,能走大格子就走大格子

如果起点和终点在小格子中,先走到附近的大格子里面,然后查询大格子之间的最短路径,一共有 161616 条

# Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
    ll K; cin >> K;
    ll Sx, Sy, Tx, Ty; cin >> Sx >> Sy >> Tx >> Ty; Sx += K, Sy += K, Tx += K, Ty += K;
    ll dist = abs(Tx - Sx) + abs(Ty - Sy);
    if (1 < K) {
        vector<tuple<ll, ll, ll> > st;
        if (((Sx / K) ^ (Sy / K)) & 1) {
            st.emplace_back(Sx / K, Sy / K, 0);
        }
        else {
            st.emplace_back(Sx / K - 1, Sy / K, 1 + Sx % K);
            st.emplace_back(Sx / K + 1, Sy / K, K - Sx % K);
            st.emplace_back(Sx / K, Sy / K - 1, 1 + Sy % K);
            st.emplace_back(Sx / K, Sy / K + 1, K - Sy % K);
        }

        vector<tuple<ll, ll, ll> > ed;
        if (((Tx / K) ^ (Ty / K)) & 1) {
            ed.emplace_back(Tx / K, Ty / K, 0);
        }
        else {
            ed.emplace_back(Tx / K - 1, Ty / K, 1 + Tx % K);
            ed.emplace_back(Tx / K + 1, Ty / K, K - Tx % K);
            ed.emplace_back(Tx / K, Ty / K - 1, 1 + Ty % K);
            ed.emplace_back(Tx / K, Ty / K + 1, K - Ty % K);
        }

        if (K == 2) {
            for (auto [sx, sy, d1] : st)
                for (auto [tx, ty, d2] : ed)
                    dist = min(dist, abs(sx - tx) + abs(sy - ty)  + abs (abs(sx - tx) - abs(sy - ty)) / 2 + d1 + d2);
        }
        else {
            for (auto [sx, sy, d1] : st)
                for (auto [tx, ty, d2] : ed)
                    dist = min(dist, abs(sx - tx) + abs(sy - ty) + abs(abs(sx - tx) - abs(sy - ty)) + d1 + d2);
        }
    }
    cout << dist << endl;
    return 0;
}
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
44

# G - Merchant Takahashi

# Question

AtCoder 王国有 NNN 个城镇:城镇 111 、 222 、 …\ldots… 、 NNN 。从 iii 镇到 jjj 镇,必须支付 C×∣i−j∣C \times |i-j|C×∣i−j∣ 日元的过路费。

商人高桥正在考虑参加 MMM 个或更多即将到来的市场。

第 iii 个市场 (1≤i≤M)(1 \leq i \leq M)(1≤i≤M) 由一对整数 (Ti,Pi)(T_i, P_i)(Ti​,Pi​) 描述,其中市场在城镇 TiT_iTi​ 举行,如果他参加,将赚取 PiP_iPi​ 日元。

对于所有的 1≤i≤M1 \leq i \leq M1≤i≤M , iii 次市场在 (i+1)(i+1)(i+1) 次市场开始之前结束。他移动的时间可以忽略不计。

他从 101010010^{10^{100}}1010100 日元开始,最初在 111 镇。通过优化选择参与哪些市场以及如何移动,确定他可以获得的最大利润。

从形式上看,如果他在 MMM 个市场后获得最大资金额,那么 1010100+X10^{10^{100}} + X1010100+X 就是他的最终资金额。求 XXX 。

# Solution

显然 DP

定义 f[i]f[i]f[i] 表示第 iii 个活动结束后,且第 iii 个活动必须参加所能达到的最大钱数

那么 f[i]=max⁡j=1i{f[j]−C∣T[i]−T[j]∣+P[i]}f[i]=\max_{j=1}^{i}\{f[j]-C|T[i]-T[j]|+P[i]\}f[i]=maxj=1i​{f[j]−C∣T[i]−T[j]∣+P[i]}

我们可以根据 T[i]T[i]T[i] 和 T[j]T[j]T[j] 的大小分类讨论

  • T[i]>T[j]T[i]>T[j]T[i]>T[j] 时
f[i]=max⁡j=1i{f[j]+CT[j]}−CT[i]+P[i] f[i]=\max_{j=1}^{i}\{f[j]+CT[j]\}-CT[i]+P[i] f[i]=j=1maxi​{f[j]+CT[j]}−CT[i]+P[i]
  • T[i]≤T[j]T[i]\le T[j]T[i]≤T[j] 时
f[i]=max⁡j=1i{f[j]−CT[j]}+CT[i]+P[i] f[i]=\max_{j=1}^{i}\{f[j]-CT[j]\}+CT[i]+P[i] f[i]=j=1maxi​{f[j]−CT[j]}+CT[i]+P[i]

用两棵线段树维护就好了

# Code

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

const ll inf = 1e18;
const ll INF = inf * inf;
ll read() {
    ll x = 0, f = 1; char ch = getchar();
    while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
    while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();}
    return x * f;
}
void print(ll x) {
    if (x < 0) {putchar('-'); x = -x;}
    if (x > 9) print(x / 10);
    putchar(x % 10 + '0');

}
struct Segment_Tree {
    vector<ll> val;
    int n;
    Segment_Tree(int n) : n(n) {val.assign(4 * n, -INF);}
    void push_up(int x) {val[x] = max(val[x << 1], val[x << 1 | 1]);}
    ll query(int x, int l, int r, int ql, int qr) {
        if (ql <= l && r <= qr) return val[x];
        if (ql > qr) return -INF;
        ll res = -INF;
        int mid = (l + r) / 2;
        if (ql <= mid) res = max(res, query(x << 1, l, mid, ql, qr));
        if (qr > mid) res = max(res, query(x << 1 | 1, mid + 1, r, ql, qr));
        return res;
    }
    void update(int x, int l, int r, int pos, ll v) {
        if (l == r) {val[x] = v; return;}
        int mid = (l + r) / 2;
        if (pos <= mid) update(x << 1, l, mid, pos, v);
        else update(x << 1 | 1, mid + 1, r, pos, v);
        push_up(x);
    }
};

int main() {
    ll ret = 0;
    int n; cin >> n;
    ll C = read(); 
    int m; cin >> m;
    vector<ll> T(m + 1, 0ll), P(m + 1, 0ll);
    for (int i = 1; i <= m; i++)
        T[i] = read(), P[i] = read();
    Segment_Tree up(n + 1), dn(n + 1);
    up.update(1, 1, n, 1, C);
    dn.update(1, 1, n, 1, -C);
    vector<ll> dp(n + 1, -INF); dp[1] = 0;
    for (int i = 1; i <= m; i++) {
        ll ans_l = up.query(1, 1, n, 1, T[i] - 1) - C * T[i] + P[i];
        ll ans_r = dn.query(1, 1, n, T[i] + 1, n) + C * T[i] + P[i];
        ll ans = max(ans_l, ans_r);
        ans = max(ans , dp[T[i]] + P[i]);
        dp[T[i]] = max(dp[T[i]], ans);
        ret = max(ret, ans);
        up.update(1, 1, n, T[i], ans + C * T[i]);
        dn.update(1, 1, n, T[i], ans - C * T[i]);
    }
    print(ret); puts("");
    return 0;
}
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
上次更新: 2025/04/08, 18:03:31
AtCoder Beginner Contest 347 A-G 题解
AtCoder Beginner Contest 359 A-G 题解

← AtCoder Beginner Contest 347 A-G 题解 AtCoder Beginner Contest 359 A-G 题解→

最近更新
01
Java基础语法
05-26
02
开发环境配置
05-26
03
pink 老师 JavaScript 学习笔记
05-26
更多文章>
Theme by Vdoing | Copyright © 2024-2025 Martian148 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式