AtCoder Beginner Contest 252 A~G 题解
前言
- 这是我第一次写7题(A~G)的ABC题解,若有写得不好或者不到位的地方请多多指教,我将万分感激,感谢大家的支持!
ABC252 A~G
- [A - ASCII code](https://atcoder.jp/contests/abc252/tasks/abc252_a)
- 题目大意
- 输入格式
- 输出格式
- 分析
- 代码
- [B - Takahashi's Failure](https://atcoder.jp/contests/abc252/tasks/abc252_b)
- 题目大意
- 输入格式
- 输出格式
- 分析
- 代码
- [C - Slot Strategy](https://atcoder.jp/contests/abc252/tasks/abc252_c)
- 题目大意
- 输入格式
- 输出格式
- 分析
- 代码
- [D - Distinct Trio](https://atcoder.jp/contests/abc252/tasks/abc252_d)
- 题目大意
- 输入格式
- 输出格式
- 分析
- 代码
- [E - Road Reduction](https://atcoder.jp/contests/abc252/tasks/abc252_e)
- 题目大意
- 输入格式
- 输出格式
- 分析
- 代码
- [F - Bread](https://atcoder.jp/contests/abc252/tasks/abc252_f)
- 题目大意
- 输入格式
- 输出格式
- 分析
- 代码
- [G - Pre-Order](https://atcoder.jp/contests/abc252/tasks/abc252_g)
- 题目大意
- 输入格式
- 输出格式
- 分析
- 代码
A - ASCII code
题目大意
给定正整数NNN,输出ASCII码是NNN的字母。
97≤N≤12297\le N\le 12297≤N≤122
输入格式
NNN
输出格式
输出ASCII码是NNN的字母。
分析
注意a
对应979797,b
对应989898,……,z
对应122122122。
安上小白专属转换教程:
- C
int n = 97; putchar(n); /* 输出:a */
putchar
函数自动转换为字符,也可以使用printf("%c", n)
效果相同 - C++
int n = 97; cout << char(n) << endl; // 输出:a
直接
cout << n
会输出97
,需要用char
转换为字符 - Python
n = 97 print(chr(n)) # 输出:a
同样也不能直接输出,需要用
chr
转换 - Java
int n = 97; char c = (char) n; System.out.print(c);
与C++、Python类似,需要转换
- JavaScript
var n = 97; var c = String.fromCharCode(n); console.log(c); // 输出:a
同样使用接口转化,需调用
String.fromCharCode
再不懂你试试……
代码
太水,直接走一发py(现场25秒AC)
print(chr(int(input())))
B - Takahashi’s Failure
题目大意
Takahashi的房子里有NNN个食物。第iii个食物的美味度是AiA_iAi。
其中,他不喜欢KKK个食物:B1,B2,…,BKB_1,B_2,\dots,B_KB1,B2,…,BK。
已知Takahashi会从NNN个食物中随机选取一个美味度最大的食物,并把它吃掉。
Takahashi是否有可能迟到不喜欢的食物?
1≤K≤N≤1001\le K\le N\le 1001≤K≤N≤100
1≤Ai≤1001\le A_i\le 1001≤Ai≤100
1≤Bi≤N1\le B_i\le N1≤Bi≤N
输入格式
NKN~KN K
A1…ANA_1~\dots~A_NA1 … AN
B1…BKB_1~\dots~B_KB1 … BK
输出格式
如果有可能,输出Yes
;否则,输出No
。
分析
只要有不喜欢的食物美味度最高就有可能,否则不可能。详见代码。
代码
还是水,注意如果是0-indexed\text{0-indexed}0-indexed的话BiB_iBi要减111
#include <cstdio>
using namespace std;int a[105];int main()
{int n, k, mx = 0;scanf("%d%d", &n, &k);for(int i=0; i<n; i++){scanf("%d", a + i);if(a[i] > mx) mx = a[i];}while(k--){scanf("%d", &n);if(a[--n] == mx){puts("Yes");return 0;}}puts("No");return 0;
}
C - Slot Strategy
题目大意
略,请自行前往AtCoder查看。
2≤N≤1002\le N\le 1002≤N≤100
输入格式
NNN
S1S_1S1
⋮\vdots⋮
SNS_NSN
输出格式
输出答案。
分析
令cnt[i][j]=(Sk[j]=i\text{cnt}[i][j]=(S_k[j]=icnt[i][j]=(Sk[j]=i的个数))),对最终变成000-999分别计算代价即可。详见代码。
代码
#include <cstdio>
using namespace std;int cnt[10][10]; // cnt[i][j] = number of (s[j]=i)int main()
{int n;scanf("%d", &n);for(int i=0; i<n; i++){char s[15];scanf("%s", s);for(int j=0; j<10; j++)cnt[s[j] ^ 48][j] ++;}int ans = 1000;for(int i=0; i<10; i++){int cur = 0;for(int j=0; j<10; j++){int c = j + (cnt[i][j] - 1) * 10;if(c > cur) cur = c;}if(cur < ans) ans = cur;}printf("%d\n", ans);return 0;
}
D - Distinct Trio
题目大意
给定长为NNN的整数序列A=(A1,…,AN)A=(A_1,\dots,A_N)A=(A1,…,AN)。
求符合以下条件的整数对(i,j,k)(i,j,k)(i,j,k)的个数:
- 1≤i<j<k≤N1\le i<j<k\le N1≤i<j<k≤N
- Ai≠Aj≠AkA_i\ne A_j\ne A_kAi=Aj=Ak
3≤N≤2×1053\le N\le 2\times 10^53≤N≤2×105
1≤Ai≤2×1051\le A_i\le 2\times 10^51≤Ai≤2×105
输入格式
NNN
A1…ANA_1~\dots~A_NA1 … AN
输出格式
输出一行,即符合条件的整数对(i,j,k)(i,j,k)(i,j,k)的个数。
分析
本题主要有两种思路:
- 逆向思维,用总数-不符合条件的;
- 将题目转化为求Ai<Aj<AkA_i<A_j<A_kAi<Aj<Ak的(i,j,k)(i,j,k)(i,j,k)的个数。
这里介绍第一种方法(第二种方法较为简单,不详细说明)。
首先易得,总共的1≤i<j<k≤N1\le i<j<k\le N1≤i<j<k≤N有Cn3C_n^3Cn3种取法。
然后考虑Ai,Aj,AkA_i,A_j,A_kAi,Aj,Ak中有重复的个数:
- 对于AAA中每个数xxx,我们记录cntx=A\text{cnt}_x=Acntx=A中xxx出现的次数;
- 然后,如果cntx≥2\text{cnt}_x\ge 2cntx≥2,则将答案减去Ccntx2×(N−cntx)C_{\text{cnt}_x}^2\times(N-\text{cnt}_x)Ccntx2×(N−cntx),即x,x,yx,x,yx,x,y格式出现的次数;
- 又如果cntx≥3\text{cnt}_x\ge 3cntx≥3,将答案减去Ccntx3C_{\text{cnt}_x}^3Ccntx3,即x,x,xx,x,xx,x,x的次数。
总时间复杂度为O(N+maxA−minA)\mathcal O(N+\max_A-\min_A)O(N+maxA−minA),空间复杂度为O(maxA−minA)\mathcal O(\max_A-\min_A)O(maxA−minA)。
代码
#include <cstdio>
#define maxn 200005
using namespace std;using LL = long long;
int cnt[maxn];inline LL C2(int n) { return n * (n - 1LL) >> 1LL; }
inline LL C3(int n) { return C2(n) * (n - 2LL) / 3LL; }int main()
{int n;scanf("%d", &n);for(int i=0; i<n; i++){int a;scanf("%d", &a);cnt[a] ++;}LL ans = C3(n);for(int i=1; i<maxn; i++)if(cnt[i] > 1){ans -= C2(cnt[i]) * (n - cnt[i]);if(cnt[i] > 2) ans -= C3(cnt[i]);}printf("%lld\n", ans);return 0;
}
E - Road Reduction
题目大意
给定一张由NNN个点和MMM条边组成的简单无向图。
第iii条边长度为CiC_iCi,同时连接点AiA_iAi和BiB_iBi。
求任意一颗生成树,使得从点111到其他所有点的距离之和最小。
2≤N≤2×1052\le N\le 2\times 10^52≤N≤2×105
N−1≤M≤2×105N-1\le M\le 2\times 10^5N−1≤M≤2×105
1≤Ai<Bi≤N1\le A_i<B_i\le N1≤Ai<Bi≤N
(Ai,Bi)≠(Aj,Bj)(A_i,B_i)\ne(A_j,B_j)(Ai,Bi)=(Aj,Bj)(i≠ji\ne ji=j)
1≤Ci≤1091\le C_i\le 10^91≤Ci≤109
输入格式
NMN~MN M
A1B1C1A_1~B_1~C_1A1 B1 C1
⋮\vdots⋮
AMBMCMA_M~B_M~C_MAM BM CM
输出格式
按任意顺序输出留下来的N−1N-1N−1条边的下标,用空格隔开。
分析
显然,在生成树中,点111到任意点的距离肯定不少于在原图中到这个点的距离。
因此,如果两个距离相等,显然就是最优解。
此时可以证明,肯定有这样的解。使用Dijkstra
算法求最短路径的同时,记录到每个点之前的最后一条路即可。
代码
Dijkstra的两种经典实现方式,O(NlogN+MlogN)\mathcal O(N\log N+M\log N)O(NlogN+MlogN)
priority_queue
优先队列(182ms182\text{ms}182ms)#include <cstdio> #include <queue> #define maxn 200005 #define INF 9223372036854775807LL using namespace std;using LL = long long; using pli = pair<LL, int>;struct Edge {int v, id; LL d;inline Edge(int u, int l, int i): v(u), d(l), id(i) {} };vector<Edge> G[maxn]; LL dis[maxn]; int ans[maxn];int main() {int n, m;scanf("%d%d", &n, &m);for(int i=1; i<=m; i++){int a, b, c;scanf("%d%d%d", &a, &b, &c);G[--a].emplace_back(--b, c, i);G[b].emplace_back(a, c, i);}priority_queue<pli, vector<pli>, greater<pli>> q;for(int i=1; i<n; i++) dis[i] = INF;q.emplace(0LL, 0);while(!q.empty()){auto [d, v] = q.top(); q.pop();if(dis[v] == d)for(const Edge& e: G[v]){LL nd = d + e.d;if(nd < dis[e.v])q.emplace(dis[e.v] = nd, e.v),ans[e.v] = e.id;}}for(int i=1; i<n; i++) printf("%d ", ans[i]);return 0; }
set
集合(202ms202\text{ms}202ms)#include <cstdio> #include <vector> #include <set> #define maxn 200005 #define INF 9223372036854775807LL using namespace std;using LL = long long; using pli = pair<LL, int>;struct Edge {int v, id; LL d;inline Edge(int u, int l, int i): v(u), d(l), id(i) {} };vector<Edge> G[maxn]; LL dis[maxn]; int ans[maxn];int main() {int n, m;scanf("%d%d", &n, &m);for(int i=1; i<=m; i++){int a, b, c;scanf("%d%d%d", &a, &b, &c);G[--a].emplace_back(--b, c, i);G[b].emplace_back(a, c, i);}set<pli> s; // <distance, vertex>for(int i=1; i<n; i++) dis[i] = INF;s.emplace(0LL, 0);while(!s.empty()){auto [d, v] = *s.begin(); s.erase(s.begin());for(const Edge& e: G[v]){LL nd = d + e.d;if(nd < dis[e.v]){if(dis[e.v] < INF)s.erase(pli(dis[e.v], e.v));s.emplace(dis[e.v] = nd, e.v);ans[e.v] = e.id;}}}for(int i=1; i<n; i++) printf("%d ", ans[i]);return 0; }
注意使用long long
。
F - Bread
题目大意
本题翻译已经过简化,部分表示与原题不同,仅供参考,请以原题为准。
有一个的整数序列SSS,初始只有一个元素LLL,我们可以执行如下操作无限次:
- 从SSS中删去任意元素kkk(k>1k>1k>1),同时选取整数xxx(1≤x≤k−11\le x\le k-11≤x≤k−1),将xxx和k−xk-xk−x放入SSS。此操作的代价为kkk。
求最小的代价,使得AAA在SSS中,即AAA中每个元素的出现次数≤S~\le S ≤S中对应元素的出现次数。
2≤N≤2×1052\le N\le 2\times 10^52≤N≤2×105
1≤N≤1091\le N\le 10^91≤N≤109
A1+A2+⋯+AN≤L≤1015A_1+A_2+\dots+A_N\le L\le 10^{15}A1+A2+⋯+AN≤L≤1015
输入格式
NLN~LN L
A1…ANA_1~\dots~A_NA1 … AN
输出格式
输出最小的代价。
分析
本题考虑逆向思维,仔细思考后发现题目可以如下转化:
- 令S=(A1,…,AN,L−∑A)S=(A_1,\dots,A_N,L-\sum A)S=(A1,…,AN,L−∑A)(L=∑AL=\sum AL=∑A时不千万不要加上最后一个元素)
- 每次操作将AAA中任意两个元素合并,它们的和即为合并后新的元素,也是本次操作的代价
- 最后发现全部合并完后SSS中正好剩下一个LLL,此时操作结束,所有代价和即为方案的最终代价。
此时,显然每次合并最小的两个数即为最优方案,因此可以使用优先队列实现,总时间复杂度为O(NlogN)\mathcal O(N\log N)O(NlogN)。
代码
注意使用long long
。
#include <cstdio>
#include <queue>
using namespace std;using LL = long long;int main()
{int n;LL l;scanf("%d%lld", &n, &l);priority_queue<LL, vector<LL>, greater<LL>> q;for(int i=0; i<n; i++){int x;scanf("%d", &x);q.push(x);l -= x;}if(l > 0) q.push(l);LL ans = 0LL;while(q.size() > 1){LL x = q.top(); q.pop();x += q.top(); q.pop();ans += x;q.push(x);}printf("%lld\n", ans);return 0;
}
G - Pre-Order
题目大意
有一颗由NNN个节点1,2,…,N1,2,\dots,N1,2,…,N组成的树,它的根节点为111。
它的先序遍历序列是(P1,P2,…,PN)(P_1,P_2,\dots,P_N)(P1,P2,…,PN)。
每次搜索时,我们都会优先前往编号小的节点。
有多少种不同的树,使其符合上述条件?对998244353998244353998244353取模。
2≤N≤5002\le N\le 5002≤N≤500
1≤Pi≤N1\le P_i\le N1≤Pi≤N
P1=1P_1=1P1=1
P1≠P2≠…≠PNP_1\ne P_2\ne\dots\ne P_NP1=P2=…=PN
输入格式
NNN
P1…PNP_1~\dots~P_NP1 … PN
输出格式
输出答案,对998244353998244353998244353取模。
分析
我们先将PPP变为0-indexed\text{0-indexed}0-indexed,即原来的(P1,P2,…,PN)(P_1,P_2,\dots,P_N)(P1,P2,…,PN)分别对应(A0,A1,…,AN−1)(A_0,A_1,\dots,A_{N-1})(A0,A1,…,AN−1)。
此时,不妨考虑区间dp\text{dp}dp的思想,设dp(l,r)=(\mathrm{dp}(l,r)=~(dp(l,r)= (一棵树已经去掉根节点的先序遍历为Al,Al+1,…,Ar−1A_l,A_{l+1},\dots,A_{r-1}Al,Al+1,…,Ar−1的可能数))),则dp(1,N)\mathrm{dp}(1,N)dp(1,N)即为所求。
下面考虑dp(l,r)\mathrm{dp}(l,r)dp(l,r)的动态转移方程。
- 先考虑AlA_lAl为Al+1,…,Ar−1A_{l+1},\dots,A_{r-1}Al+1,…,Ar−1的祖宗的情况,如图:
易得,此时dp(l,r)\mathrm{dp}(l,r)dp(l,r)初始化为dp(l+1,r)\mathrm{dp}(l+1,r)dp(l+1,r)。 - 再考虑区分左右子树,对于每个kkk(l<k<rl<k<rl<k<r),将Al,…,Ak−1A_l,\dots,A_{k-1}Al,…,Ak−1当作左子树(可能数为dp(l+1,k)\mathrm{dp}(l+1,k)dp(l+1,k)),再将Ak,…,Ar−1A_k,\dots,A_{r-1}Ak,…,Ar−1当作右子树(可能数为dp(k,r)\mathrm{dp}(k,r)dp(k,r)),此时如果Al<AkA_l<A_kAl<Ak则符合题意,将dp(l,r)\mathrm{dp}(l,r)dp(l,r)加上dp(l+1,k)×dp(k,r)\mathrm{dp}(l+1,k)\times \mathrm{dp}(k,r)dp(l+1,k)×dp(k,r)即可。
至此,本题已结束,时间复杂度为O(N3)\mathcal O(N^3)O(N3)。
代码
注意事项:
- 乘法操作需要转为
long long
再取模。 - 答案为dp(1,N)\mathrm{dp}(1,N)dp(1,N),不是dp(0,N)\mathrm{dp}(0,N)dp(0,N)。
- 注意区间dp\text{dp}dp计算顺序,参考代码提供两种写法(先枚举lll和先枚举长度)。
- 写法一(先枚举lll,59ms59\text{ms}59ms)
#include <cstdio> #define MOD 998244353 #define maxn 505 using namespace std;using LL = long long; int p[maxn], dp[maxn][maxn];int main() {int n;scanf("%d", &n);for(int i=0; i<n; i++)scanf("%d", p + i);for(int l=n; l>0; l--){dp[l][l] = 1;for(int r=l+1; r<=n; r++){dp[l][r] = dp[l + 1][r];for(int k=l+1; k<r; k++)if(p[l] < p[k] && (dp[l][r] += LL(dp[l + 1][k]) * dp[k][r] % MOD) >= MOD)dp[l][r] -= MOD;}}printf("%d\n", dp[1][n]);return 0; }
- 写法二(先枚举长度,66ms66\text{ms}66ms)
#include <cstdio> #define MOD 998244353 #define maxn 505 using namespace std;using LL = long long; int p[maxn], dp[maxn][maxn];int main() {int n;scanf("%d", &n);for(int i=0; i<n; i++)scanf("%d", p + i);for(int i=1; i<=n; i++)dp[i][i] = 1;for(int d=1; d<=n; d++)for(int l=1, r=d+1; r<=n; l++, r++){dp[l][r] = dp[l + 1][r];for(int k=l+1; k<r; k++)if(p[l] < p[k] && (dp[l][r] += LL(dp[l + 1][k]) * dp[k][r] % MOD) >= MOD)dp[l][r] -= MOD;}printf("%d\n", dp[1][n]);return 0; }
AtCoder Beginner Contest 252 A~G 题解相关推荐
- AtCoder Beginner Contest 246 A~E 题解 Bishop 2
AtCoder Beginner Contest 246 A~E 题解 A Four Points 题意 给你矩形的三个顶点,输出剩下那个 思路 把横坐标和纵坐标分开,必会存在两个相同的数,横纵坐标就 ...
- AtCoder Beginner Contest 242 C~E 题解
ABC242 C~E [C - 1111gal password](https://atcoder.jp/contests/abc242/tasks/abc242_c) 题目大意 输入格式 输出格式 ...
- AtCoder Beginner Contest 254 A~E 题解
ABC254 A~E [A - Last Two Digits](https://atcoder.jp/contests/abc254/tasks/abc254_a) 题目大意 输入格式 输出格式 样 ...
- AtCoder Beginner Contest 204 A~E 题解
ABC204 A~E [A - Rock-paper-scissors](https://atcoder.jp/contests/abc204/tasks/abc204_a) 题目大意 输入格式 输出 ...
- AtCoder Beginner Contest 198 A~E题解
ABC198 A~E [A - Div](https://atcoder.jp/contests/abc198/tasks/abc198_a) 题目大意 输入格式 输出格式 样例 分析 代码 [B - ...
- Mynavi Programming Contest 2021 (AtCoder Beginner Contest 201) A~E 题解
ABC201/Mynavi2021 A~E [A - Tiny Arithmetic Sequence](https://atcoder.jp/contests/abc201/tasks/abc201 ...
- AtCoder Beginner Contest 196 A~E题解
ABC196 A~E [A - Difference Max](https://atcoder.jp/contests/abc196/tasks/abc196_a) 题目大意 输入格式 输出格式 样例 ...
- AtCoder Beginner Contest 260 A~F 题解
ABC260 A~F [A - A Unique Letter](https://atcoder.jp/contests/abc260/tasks/abc260_a) 题目大意 输入格式 输出格式 样 ...
- AtCoder Beginner Contest 253 A~E 题解
ABC253 A~E [A - Median?](https://atcoder.jp/contests/abc253/tasks/abc253_a) 题目大意 输入格式 输出格式 样例 分析 代码 ...
最新文章
- 2020秋季-人工神经网络课程报告
- IOS CALayer
- 精准扶贫探索新融合模式-农业大健康·李龙:谋定乡村振兴
- 企业建立数据驱动决策该如何做?终于有大神总结全了
- Qt QSetting *.ini.lock
- 使用Apriori进行关联分析(一)
- url参数拼接 php,PHP解析url并得到url参数方法总结
- java技术秘籍 转摘
- ARCH与GARCH模型
- 动态组合sql语句详解
- 秩和比(RSR)指标计算
- vue3 ts three 动画 骨骼动画 人物动画 模型动画
- SDL 加载显示JPEG图片
- c语言程序运行超时是怎么回事,这个运行超时是什么原因?求助~
- 微信小程序导入Bmob后端云的步骤
- Ashen的成长,从CSDN博客开始!
- X86_64 GNU汇编、寄存器、内嵌汇编
- 23-1-18 PDManer 工具
- gitHub不能用密码推送了,必须要使用令牌
- 嵌入式Linux驱动编程复习资料