首页 > 其他分享 >Atcoder Beginner Contest 353

Atcoder Beginner Contest 353

时间:2024-05-12 19:30:03浏览次数:10  
标签:Atcoder Beginner 10 int sum 353 ans ll mod

Atcoder Beginner Contest 353

A

问题陈述

有 \(N\) 幢楼房排列成一排。左起的 \(i\) th楼高 \(H_i\) 。

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

思路

签到题。

代码

#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\) 组有 \((1\leq i\leq N)\) 人。对于所有 \(i\) \((1\leq i\leq N)\) ,都成立 \(A_i \leq K\) 。

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

最初,没有人被引导到景点,有 \(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

问题陈述

对于正整数 \(x\) 和 \(y\) ,定义 \(f(x, y)\) 为 \((x + y)\) 除以 \(10^8\) 的余数。

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

\(\displaystyle \sum_{i=1}^{N-1}\sum_{j=i+1}^N f(A_i,A_j)\)
\(1 \le A_i < 10^8\)

思路

注意到每个数都小于模数,所以 \((A_i+A_j) \mod 10^8\) 只可能等于 \(A_i+A_i\) 或 \(A_i+A_j-10^8\) 。

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

排序后,对于每个 \(A_i\),把它和 \(A_{1,\ldots,i-1}\) 求和,减去的 \(10^8\),可以通过二分求出大于等于 \(10^8-A_i\) 的数的个数。剩余部分可用前缀和完成。

代码

#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

问题陈述

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

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

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

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

\(\displaystyle \sum_{i=1}^{N-1}\sum_{j=i+1}^N f(A_i,A_j)\)

思路

记 \(c(A_i)\) 为 \(A_i\) 位数,\(w(A_i)\) 为 \(A_i\) 的位权,\(w(A_i)=10^{c(A_i)}\)。

有 \(f(A_i,A_j)=A_i·w(A_j)+A_j\)。

原式

\(=\displaystyle \sum_{i=1}^{N-1}\sum_{j=i+1}^N f(A_i,A_j)\)

\(=\displaystyle\sum_{i=1}^{N-1}\sum_{j=i+1}^N A_i·w(A_j)+A_j\)

\(=\displaystyle\sum_{i=1}^{N-1}A_i·\sum_{j=i+1}^N w(A_j)+\sum_{j=i+1}^N A_j\)

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

代码

#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

问题陈述

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

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

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

\(\displaystyle \sum_{i=1}^{N-1}\sum_{j=i+1}^N f(S_i,S_j)\)

思路

看到最长公共前缀,想到使用Trie维护。把 \(N\) 个字符串建在一颗Trie里,维护经过每条边的字符串的个数 \(c_i\) ,则每条边对答案的贡献为 \(\frac{c_i(c_i-1)}{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\) 个城镇:城镇 \(1\) 、 \(2\) 、 \(\ldots\) 、 \(N\) 。从 \(i\) 镇到 \(j\) 镇,必须支付 \(C \times |i-j|\) 日元的过路费。

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

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

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

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

从形式上看,如果他在 \(M\) 个市场后拥有的资金量最大,那么 \(10^{10^{100}} + X\) 就是他的最终资金量。求 \(X\) 。

思路

定义 \(dp_{T_i}\) 表示考虑到前 \(i\) 个市场的最大收益。

\[dp_{T_i}=\max_{1\le j < i} dp_{T_j}-C·|T_i-T_j|+P_i \]

变形后可得:

\[dp_{T_i}=\max (\max_{1\le j <i,1\le T_j \le T_i} dp_{T_j}-CT_i+CT_j+P_i) (\max_{1\le j <i,T_i\le T_j \le n} dp_{T_j}+CT_i-CT_j+P_i) \]

移除与 \(j\) 无关的项,可以发现取 \(\max\) 的式子有 \(dp_{T_j}+CT_j\) \(dp_{T_j}-CT_j\) 。

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

代码

#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;
}

标签:Atcoder,Beginner,10,int,sum,353,ans,ll,mod
From: https://www.cnblogs.com/maniubi/p/18188086

相关文章

  • ABC353 | 如同流星划过天空
    ABC353|如同流星划过天空A.&B.依题意模拟即可。C.注意只有\(f(x,y)\)需要对\(10^8\)取模,\(f\)的求和不需要。关注到\(a_i\in[1,10^8)\),故\(a_i+a_j\in[2,2\times10^8)\)。从而\(f(x,y)=[x+y<10^8](x+y)+[x+y\ge10^8](x+y-10^8)=x+y-10^8[x+y\ge10^......
  • ABC353C Sigma Problem 题解
    ABC353CSigmaProblem题解题目链接:AT题目中的两个求和符号\(\sum_{i=1}^{N-1}\sum_{j=i+1}^{N}\)实际上是在枚举所有的有序数对\((i,j)\)。而有序数对的个数\(N(N-1)/2=O(N^{2})\),真的去枚举所有数对肯定会T。这时应该考虑去拆贡献,求出每个\(A_i\)对答案的贡献。......
  • AtCoder Beginner Contest 353
    AtCoderBeginnerContest353A-Buildings求第一个\(h_i\)大于\(h_1\)的位置。模拟。点击查看代码#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;intn,h[103];signedmain(){ cin>>n;cin>>h[1]; for(inti=2;i<=n;i++){ cin&......
  • AtCoder Beginner Contest 353
    A-Buildings(abc353A)题目大意给定\(n\)个数字,输出第一个大于第一个数的下标。解题思路依次与第一个数比较,大于则输出。神奇的代码n=input()a=list(map(int,input().split()))b=[i>a[0]foriina]ifTruenotinb:print(-1)else:print(b.ind......
  • ABC353E字典树处理最长公共前缀
    https://atcoder.jp/contests/abc353/tasks/abc353_e其实就是字典树板子题。似乎遇到最长公共前缀,就该想到字典树。依次加入每个字符串:维护一个数组siz来统计在当前串之前的串在对应点的出现次数。手模一下字典树的建树过程,显然如果当前串\(S_i\)能跑到一个曾经串\(S_......
  • ABC353
    不知道为啥有断更了一周...Ewoc,怎么跟我出的题目这么像先把字符串扔到一个Trie里面,然后对于每一个点我们考虑这一个点到根节点组成的字符串能是多少对字符串的最长公共前缀。我们定义\(cnt_u\)表示共有多少个字符串的结尾在以\(u\)为根的子树内。对于\(u\)节点,其贡献......
  • AtCoder Beginner Contest 318 Ex Count Strong Test Cases
    洛谷传送门AtCoder传送门首先做一些初步的观察:A和B的解法是对称的,所以A对的方案数等于B对的方案数。同时若A和B同时对则每个置换环环长为\(1\),方案数为\(n!\)。所以,若设A对的方案数为\(x\),那么答案为\(n!^2-(x-n!)-(x-n!)-n!=n!^2+n!-x\)。......
  • ATcoder ABC 352 F - Estimate Order 搜索
    很恶心的一个搜索,当然好像不用搜索也能做。没啥好讲的,一个联通块大小>=2就要搜索找位置,联通块大小等于1的不用搜。能调出来也是真不容易。#include<bits/stdc++.h>#defineintlonglong#defineDBdoubleusingnamespacestd;intn,m,tsiz,yinum;constintN=23;intfa[......
  • AtCoder Beginner Contest 352
    AtCoderBeginnerContest352A-AtCoderLine给\(N,X,Y,Z\)判断是否\(\min(X,Y)\leZ\le\max(X,Y)\)。模拟。点击查看代码#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;intn,x,y,z;signedmain(){ cin>>n>>x>>y>......
  • AtCoder Grand Contest 001
    D.ArraysandPalindrome如果两个字符要求相同就给它们连边,对于一个长度为\(x\)的回文串,\(x\)是偶数会连\(x/2\)条边,奇数会连\(x/2-0.5\)条边。\(a\)和\(b\)两个序列总和为\(2n\),要让\(n\)个字符相同至少连\(n-1\)条边,也就是奇数个数超过\(2\)时一定无解......