AtCoder Beginner Contest 340 考试总结
前言
可惜的是我是VP的,却打得相对较好(服了。
得分明细:
A | B | C | D | E | F | G | Total |
---|---|---|---|---|---|---|---|
√ | √ | √ | √ | √ | √ | × | 2625 |
改题明细:
A | B | C | D | E | F | G |
---|---|---|---|---|---|---|
√ | √ | √ | √ | √ | √ | × |
第一次打 AT,发挥还可以。
A. Arithmetic Progression
Problem
打印一个包含第一项 \(A\),最后一项 \(B\) 和公差 \(C\) 的算术序列。
Solve
模拟
Code
#include <bits/stdc++.h>
#define ll long long
#define H 19260817
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define MOD 1000003
#define mod 1000000007
using namespace std;
namespace Read {
template <typename T>
inline void read(T &x) {
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x*=f;
}
template <typename T, typename... Args>
inline void read(T &t, Args&... args) {
read(t), read(args...);
}
}
using namespace Read;
void print(int x){
if(x<0){putchar('-');x=-x;}
if(x>9){print(x/10);putchar(x%10+'0');}
else putchar(x+'0');
return;
}
int a, b, c;
signed main() {
read(a, b, c);
for (int i = a; i <= b; i += c) cout << i << ' ';
cout << '\n';
return 0;
}
B. Append
Problem
初始给定空序列 \(A\),\(q\) 次操作:
1 x
在序列末尾插入数字 \(x\);2 k
查询从后往前第 \(k\) 个数字是多少;
保证合法。
Solve
又是模拟
Code
#include <bits/stdc++.h>
#define ll long long
#define H 19260817
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define MOD 1000003
#define mod 1000000007
using namespace std;
namespace Read {
template <typename T>
inline void read(T &x) {
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x*=f;
}
template <typename T, typename... Args>
inline void read(T &t, Args&... args) {
read(t), read(args...);
}
}
using namespace Read;
void print(int x){
if(x<0){putchar('-');x=-x;}
if(x>9){print(x/10);putchar(x%10+'0');}
else putchar(x+'0');
return;
}
const int N = 105;
int q, a[N], n;
signed main() {
read(q);
while(q--) {
int op, x;
read(op, x);
if(op == 1) {
a[++n] = x;
} else {
cout << a[n - x + 1] << '\n';
}
}
return 0;
}
C. Divide and Divide
Problem
给定一个数 \(n\),写在黑板上。每次选择黑板上一个不小于 \(1\) 的数 \(x\) 擦去,并写上 \(\left\lfloor\frac{x}{2}\right\rfloor\) 与 \(\left\lceil\frac{x}{2}\right\rceil\),并付出代价 \(x\)。问最后使黑板上的数全部小于 \(1\) 的代价是多少。
Solve
记 \(f_i\) 表示给定的数为 \(i\) 时的代价。
这样显然有(最优)子结构。可以 \(dp\):
先暴搜,然后暴搜转记搜。
时间复杂度 \(O(\log n)\)。
Code
#include <bits/stdc++.h>
#define int long long
#define H 19260817
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define MOD 1000003
#define mod 1000000007
using namespace std;
namespace Read {
template <typename T>
inline void read(T &x) {
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x*=f;
}
template <typename T, typename... Args>
inline void read(T &t, Args&... args) {
read(t), read(args...);
}
}
using namespace Read;
void print(int x){
if(x<0){putchar('-');x=-x;}
if(x>9){print(x/10);putchar(x%10+'0');}
else putchar(x+'0');
return;
}
const int N = 1e5 + 10;
int n, ans;
map<int, int> f;
int solve(int x) {
if(x < 2) return 0;
if(f[x]) return f[x];
return f[x] = solve(x / 2) + solve(ceil(1.0 * x / 2)) + x;
}
signed main() {
read(n);
cout << solve(n) << '\n';
return 0;
}
D. Super Takahashi Bros
Problem
高桥正在玩一个游戏。
游戏由编号为 \(1,2,3\dots,n\) 的 \(n\) 个阶段组成。最初,只有阶段 \(1\) 可以玩。
对于每个阶段 \(i\),可执行两种操作之一:
- 花费 \(A_i\) 秒清除阶段 \(i\)。这样就可以进入 \(i+1\) 阶段。
- 花费 \(B_i\) 秒清除阶段 \(i\)。这样就可以进入 \(X_i\) 阶段。
至少需要多少秒才能通关 \(n\)?
Solve
对于每个阶段的操作,都有两种转移状态:
- 花费 \(A_i\) 秒清除阶段 \(i\)。这样就可以进入 \(i+1\) 阶段。
- 花费 \(B_i\) 秒清除阶段 \(i\)。这样就可以进入 \(X_i\) 阶段。
显然,阶段与阶段之间构成图论关系。因此建图。
考虑到求最小时间。所以建图后跑最短路即可。
时间复杂度 \(O(n\log n)\)。
Code
#include <bits/stdc++.h>
#define int long long
#define H 19260817
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define MOD 1000003
#define mod 1000000007
using namespace std;
namespace Read {
template <typename T>
inline void read(T &x) {
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x*=f;
}
template <typename T, typename... Args>
inline void read(T &t, Args&... args) {
read(t), read(args...);
}
}
using namespace Read;
void print(int x){
if(x<0){putchar('-');x=-x;}
if(x>9){print(x/10);putchar(x%10+'0');}
else putchar(x+'0');
return;
}
const int N = 2e5 + 10;
struct Node {
int v, w, nx;
bool operator < (const Node &x) const {
return x.w < w;
}
} e[N << 1];
int n, h[N], tot, dis[N];
bool vis[N];
void add(int u, int v, int w) {
e[++tot] = (Node){v, w, h[u]};
h[u] = tot;
}
void dijkstra() {
memset(dis, 0x3f, sizeof dis);
dis[1] = 0;
priority_queue<Node> q;
q.push((Node){1, 0});
while(!q.empty()) {
int x = q.top().v;
q.pop();
if(vis[x]) continue;
for (int i = h[x]; i; i = e[i].nx) {
int y = e[i].v, w = e[i].w;
if(dis[y] > dis[x] + w) {
dis[y] = dis[x] + w;
q.push((Node){y, dis[y]});
}
}
}
}
signed main() {
read(n);
For(i,1,n-1) {
int a, b, x;
read(a, b, x);
add(i, i + 1, a);
add(i, x, b);
}
dijkstra();
cout << dis[n] << '\n';
return 0;
}
E. Mancala 2
Problem
有 \(N\) 个编号为 \(0\) 至 \(N-1\) 的盒子。最初,\(i\) 盒里有 \(A_i\) 个球。
高桥将依次对 \(i=1,2,\ldots,M\) 进行以下操作:
- 将变量 \(C\) 设为 \(0\)。
- 从盒子 \(B_i\) 中取出所有的球并握在手中。
- 在手拿至少一个球的同时,重复下面的过程:
- 将 \(C\) 的值增加 \(1\)。
- 将手中的一个球放入盒子 \((B_i+C) \bmod N\)。
完成所有操作后,确定每个盒子中的球数。
Solve
若把序列 \(0\) 到 \(N-1\) 顺时针看成环,则操作在环上顺时针进行。
考虑贡献的形式,每次我只会在盒子中放入一个球。操作在环上连续,则在序列上为前缀 \(+\) 后缀 \(+\) 全局加的形式。
计算出每轮操作的起点,终点,周期。则可以用线段树维护(建议用树状数组,不然常数一坨屎)。
Code
#include <bits/stdc++.h>
#define int long long
#define H 19260817
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define MOD 1000003
#define mod 1000000007
#define ls p<<1
#define rs p<<1|1
using namespace std;
namespace Read {
template <typename T>
inline void read(T &x) {
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x*=f;
}
template <typename T, typename... Args>
inline void read(T &t, Args&... args) {
read(t), read(args...);
}
}
using namespace Read;
void print(int x){
if(x<0){putchar('-');x=-x;}
if(x>9){print(x/10);putchar(x%10+'0');}
else putchar(x+'0');
return;
}
const int N = 2e5 + 10;
struct Node {
int l, r, val, add;
} t[N << 2];
int n, m, a[N], C;
void pushup(int p) {
t[p].val = t[ls].val + t[rs].val;
}
void pushdown(int p) {
if(t[p].add) {
t[ls].val += t[p].add * (t[ls].r - t[ls].l + 1);
t[rs].val += t[p].add * (t[rs].r - t[rs].l + 1);
t[ls].add += t[p].add;
t[rs].add += t[p].add;
t[p].add = 0;
}
return ;
}
void build(int p, int l, int r) {
t[p].l = l, t[p].r = r;
if(l == r) {
t[p].val = a[l-1];
return ;
}
int mid = l + r >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
pushup(p);
}
void upd(int p, int l, int r, int k) {
if(l <= t[p].l && t[p].r <= r) {
t[p].val += k * (t[p].r - t[p].l + 1);
t[p].add += k;
return ;
}
pushdown(p);
int mid = (t[p].l + t[p].r) >> 1;
if(l <= mid) upd(ls, l, r, k);
if(r > mid) upd(rs, l, r, k);
pushup(p);
}
int qry(int p, int x) {
if(t[p].l == t[p].r) {
return t[p].val;
}
pushdown(p);
int mid = (t[p].l + t[p].r) >> 1;
if(x <= mid) return qry(ls, x);
else return qry(rs, x);
}
void clean(int p, int x) {
if(t[p].l == t[p].r) {
t[p].val = 0; return ;
}
pushdown(p);
int mid = (t[p].l + t[p].r) >> 1;
if(x <= mid) clean(ls, x);
else clean(rs, x);
pushup(p);
}
signed main() {
read(n, m);
For(i,0,n-1) read(a[i]);
build(1, 1, n);
For(i,1,m) {
int b, all, L, R, tot = 0;
read(b);
all = qry(1, b + 1);
clean(1, b + 1);
L = (b + 1) % n + 1;
R = (b + all) % n + 1;
tot = all / n;
if(tot < 1) {
if(L <= R) upd(1, L, R, 1);
else {
upd(1, L, n, 1);
upd(1, 1, R, 1);
}
} else {
tot = (all - n + L - 1 - R) / n;
upd(1, L, n, 1);
upd(1, 1, n, tot);
upd(1, 1, R, 1);
}
}
For(i,1,n) cout << qry(1, i) << ' ';
return 0;
}
F. S = 1
Problem
给你整数 \(X\) 和 \(Y\),它们至少满足 \(X \neq 0\) 和 \(Y \neq 0\) 中的一个。
请找出一对满足以下所有条件的整数 \((A, B)\)。如果不存在这样的一对,请报告。
- \(-10^{18} \leq A, B \leq 10^{18}\).
- 顶点位于 \(xy\) 平面上点 \((0, 0), (X, Y), (A, B)\) 的三角形的面积为 \(1\).
Solve
对于点 \((0, 0), (X, Y), (A, B)\) 所围成的三角形面积计算公式为 \(\frac{1}{2}|XB-YA|\)。
\(S=1\) 代入上式得:\(|XB-YA|=2\)。
绝对值随便取(两种情况皆可以),于是得到 \(XB-YA=2\)
扩展欧几里得定理即可解决。
Code
#include <bits/stdc++.h>
#define int long long
#define H 19260817
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define MOD 1000003
#define mod 1000000007
using namespace std;
namespace Read {
template <typename T>
inline void read(T &x) {
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x*=f;
}
template <typename T, typename... Args>
inline void read(T &t, Args&... args) {
read(t), read(args...);
}
}
using namespace Read;
void print(int x){
if(x<0){putchar('-');x=-x;}
if(x>9){print(x/10);putchar(x%10+'0');}
else putchar(x+'0');
return;
}
int a, b, x, y;
void exgcd(int a, int b) {
if(!b) {
x = 1, y = 0;
return ;
}
exgcd(b, a % b);
int t = y;
y = x - a / b * t, x = t;
return ;
}
signed main() {
read(a, b);
if(2 % __gcd(a, -b)) {
puts("-1"); return 0;
}
exgcd(a, -b);
cout << 2 / __gcd(a, -b) * y << ' ' << 2 / __gcd(a, -b) * x << '\n';
return 0;
}
G. Leaf Color
Problem
有一棵树 \(T\) 有 \(N\) 个顶点,编号从 \(1\) 到 \(N\)。连接顶点 \(u_i\) 和 \(v_i\) 的是 \(i\) 边。此外,顶点 \(i\) 被涂上了颜色 \(A_i\)。
求满足以下条件的顶点集合 \(T\) 的(非空)子集 \(S\) 的个数(模为 \(998244353\)):
- \(T\) 的子图 \(G\) 由 \(S\) 引导,满足以下所有条件:
- \(G\) 是一棵树。
- 所有阶数为 \(1\) 的顶点颜色相同。
Solve
(咕咕咕...)
Code
(咕咕咕...)