Atcoder Beginner Contest 353

Atcoder Beginner Contest 353

A

问题陈述

N 幢楼房排列成一排。左起的 i th楼高 Hi

请判断是否有比左起第一座高的建筑物。如果存在这样的建筑物,请找出从左边起最左边的建筑物的位置。

思路

签到题。

代码

#include <bits/stdc++.h>
using namespace std;
int main() {
    int n, mx = -1, id = -1;
    cin >> n;
    for (int i = 1, a; i <= n; i ++) {
        cin >> a;
        if (i == 1) mx = a;
        if (a > mx) {
            mx = a, id = i;
            break;
        }
    }
    cout << id << endl;
    return 0;
}

B

问题陈述

AtCoder 游乐园有一个可容纳 K 人的景点。现在,有 N 组游客在排队等候进入该景点。

排在最前面的 i 组有 (1iN) 人。对于所有 i (1iN) ,都成立 AiK

高桥作为该景点的工作人员,将按照以下程序引导各组游客排队。

最初,没有人被引导到景点,有 K 个空座位。

  1. 如果排队队伍中没有团体,则启动景点并结束引导。
    1. 将景点中的空座位数量与排队队伍前方的团队人数进行比较,然后执行以下操作之一:
    • 如果空座位数量少于排在队伍前列的人数,则启动景点。然后,空座位数量再次变为 K
    • 否则,引导排在队伍最前面的整组人前往景点。排在最前面的那组游客将被移出队列,空座位数量将按照该组游客的人数减少。
  2. 返回步骤 1。

在此,引导开始后不会再有其他小组排队。在这些条件下,可以证明这一过程将在有限步数内结束。

确定在整个引导过程中要启动多少次吸引力。

思路

模拟。

代码

#include <bits/stdc++.h>
using namespace std;
int n, k, a[105], ans = 1, now, p = 1;
int main() {
    cin >> n >> k;
    for (int i = 1; i <= n; i ++) cin >> a[i];
    now = k;
    while (1) {
        if (p == n + 1) break;
        if (a[p] > now) {
            ans ++;
            now = k;
            continue;
        }
        now -= a[p], p ++;
    } 
    cout << ans << endl;
    return 0;
}

C

问题陈述

对于正整数 xy ,定义 f(x,y)(x+y) 除以 108 的余数。

给你一个长度为 N 的正整数序列 A=(A1,,AN) 。求下面表达式的值:

i=1N1j=i+1Nf(Ai,Aj)
1Ai<108

思路

注意到每个数都小于模数,所以 (Ai+Aj)mod108 只可能等于 Ai+AiAi+Aj108

注意到每个数都会与其他的数做一次加法,而加法具有交换律,所以可以将原数列排序而不影响答案。

排序后,对于每个 Ai,把它和 A1,,i1 求和,减去的 108,可以通过二分求出大于等于 108Ai 的数的个数。剩余部分可用前缀和完成。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e8;
const int N = 3e5 + 5;
ll n, a[N], ans, sum;
int main() {
    cin >> n;
    for (int i = 1; i <= n; i ++) cin >> a[i];
    sort(a + 1, a + n + 1);
    sum = a[1];
    for (int i = 2, pos; i <= n; i ++) {
        pos = upper_bound(a + 1, a + i, mod - a[i] - 1) - a;
        ans += (i - 1) * a[i] + sum - (i - pos) * mod;
        sum += a[i];
    }
    cout << ans << endl;
    return 0;
}

D

问题陈述

对于正整数 xy ,定义 f(x,y) 如下:

  • xy 的十进制表示解释为字符串,并按此顺序连接,得到字符串 z 。将 f(x,y) 解释为十进制整数时,其值就是 z 的值。

例如, f(3,14)=314f(100,1)=1001

给你一个长度为 N 的正整数序列 A=(A1,,AN) 。求下面表达式取模 998244353 的值:

i=1N1j=i+1Nf(Ai,Aj)

思路

c(Ai)Ai 位数,w(Ai)Ai 的位权,w(Ai)=10c(Ai)

f(Ai,Aj)=Ai·w(Aj)+Aj

原式

=i=1N1j=i+1Nf(Ai,Aj)

=i=1N1j=i+1NAi·w(Aj)+Aj

=i=1N1Ai·j=i+1Nw(Aj)+j=i+1NAj

分别用两个前缀和维护位权以及和即可。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
const int N = 3e5 + 5;
ll n, a[N], b[N], c[N], ans;
ll getw(ll x) {
    ll res = 1;
    while (x) res *= 10, res %= mod, x /= 10;
    return res;
}
int main() {
    cin >> n;
    for (int i = 1; i <= n; i ++) cin >> a[i];
    for (int i = n; i >= 1; i --) {
        b[i] = b[i + 1] + a[i], b[i] %= mod;
        c[i] = c[i + 1] + getw(a[i]), c[i] %= mod;
    } 
    for (int i = 1; i < n; i ++) 
        ans += b[i + 1] + a[i] * c[i + 1] % mod, ans %= mod;
    cout << ans << endl;
    return 0;
}

E

问题陈述

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

  • f(x,y)xy 的最长公共前缀的长度。

给定由小写英文字母组成的 N 字符串 (S1,,SN) 。求以下表达式的值:

i=1N1j=i+1Nf(Si,Sj)

思路

看到最长公共前缀,想到使用Trie维护。把 N 个字符串建在一颗Trie里,维护经过每条边的字符串的个数 ci ,则每条边对答案的贡献为 ci(ci1)2 。因为每个字符串都会与其它字符串产生 1 的贡献,会重复一次,故除二。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5 + 5;
int n, son[N][27], cnt = 1; ll sum[N], ans;
void insert(const string& s) {
    int p = 1;
    for (int i = 0; i < s.size(); i ++) {
        char c = s[i];
        if (!son[p][c - 'a']) son[p][c - 'a'] = ++ cnt;
        sum[son[p][c - 'a']] ++;
        p = son[p][c - 'a'];
    }
} 
void dfs(int p) {
    if (p ^ 1) ans += sum[p] * (sum[p] - 1) / 2;
    for (int i = 0; i < 26; i ++) {
        if (!son[p][i]) continue;
        dfs(son[p][i]);
    }
}
int main() {
    cin >> n;
    string s;
    for (int i = 1; i <= n; i ++) {
        cin >> s;
        insert(s);
    }
    dfs(1);
    cout << ans << endl;
    return 0;
}

F

未做出,待补。

G

问题陈述

AtCoder 王国有 N 个城镇:城镇 12N 。从 i 镇到 j 镇,必须支付 C×|ij| 日元的过路费。

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

i /-市场 (1iM) 由一对整数 (Ti,Pi) 描述,其中市场在城镇 Ti 举行,如果他参加将赚取 Pi 日元。

在所有 1i<M 中, i (次)市场在 (i+1) (次)市场开始之前结束。他移动的时间可以忽略不计。

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

从形式上看,如果他在 M 个市场后拥有的资金量最大,那么 1010100+X 就是他的最终资金量。求 X

思路

定义 dpTi 表示考虑到前 i 个市场的最大收益。

dpTi=max1j<idpTjC·|TiTj|+Pi

变形后可得:

dpTi=max(max1j<i,1TjTidpTjCTi+CTj+Pi)(max1j<i,TiTjndpTj+CTiCTj+Pi)

移除与 j 无关的项,可以发现取 max 的式子有 dpTj+CTj dpTjCTj

用线段树维护这两个内容即可。时间复杂度 O(mlogn)

代码

#include <bits/stdc++.h>
#define INF LONG_LONG_MAX
#define int long long
using namespace std;
const int N = 2e5 + 5;
int n, c, m, t[N], p[N], ans;
struct segt {
    struct node {
        int l, r, mx;
    } t[N << 2];
    #define ls (p << 1)
    #define rs (p << 1 | 1)
    void build(int p, int l, int r) {
        t[p].l = l, t[p].r = r, t[p].mx = -INF;
        if (l == r) return ;
        int mid = (l + r) >> 1;
        build(ls, l, mid);
        build(rs, mid + 1, r);
    }
    int query(int p, int l, int r) {
        if (l <= t[p].l && t[p].r <= r) return t[p].mx;
        int res = -INF;
        if (t[ls].r >= l) res = max(res, query(ls, l, r));
        if (t[rs].l <= r) res = max(res, query(rs, l, r));
        return res;
    }
    void modify(int p, int id, int v) {
        if (t[p].l == t[p].r) {
            t[p].mx = v;
            return ;
        }
        if (id <= t[ls].r) modify(ls, id, v);
        else modify(rs, id, v);
        t[p].mx = max(t[ls].mx, t[rs].mx);
    }
} F, B;
signed main() {
    cin >> n >> c >> m;
    for (int i = 1; i <= m; i ++) cin >> t[i] >> p[i];
    F.build(1, 1, n), B.build(1, 1, n);
    F.modify(1, 1, c), B.modify(1, 1, -c);
    for (int i = 1, x; i <= m; i ++) {
        x = F.query(1, 1, t[i]) - c * t[i] + p[i];
        x = max(x, B.query(1, t[i], n) + c * t[i] + p[i]);
        ans = max(ans, x);
        F.modify(1, t[i], x + c * t[i]);
        B.modify(1, t[i], x - c * t[i]);
    }
    cout << ans << endl;
    return 0;
}
posted @   maniubi  阅读(55)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示