AtCoder Beginner Contest 340
A - Arithmetic Progression
#include<bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using i128 = __int128;
using ldb = long double;
#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
using vii = vector<pii>;
const int inf = 1e9, INF = 1e18;
const int mod = 998244353;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int a, b, d;
cin >> a >> b >> d;
for (int i = a; i <= b; i += d) cout << i << " ";
return 0;
}
B - Append
#include<bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using i128 = __int128;
using ldb = long double;
#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
using vii = vector<pii>;
const int inf = 1e9, INF = 1e18;
const int mod = 998244353;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int q;
cin >> q;
vi a;
for( int op , x ; q ; q--){
cin >> op >> x;
if( op == 1 ) a.push_back(x);
else cout << *(a.end() - x) << "\n";
}
return 0;
}
C - Divide and Divide
\(f[x]\)表示移除\(x\)的代价,因此\(f[x]=x+f[\left \lfloor \frac x 2 \right \rfloor ]+f[\left \lceil \frac x 2 \right \rceil ]\)。因此很容易想到递归的求解即可,这里采用了记忆法剪枝
#include<bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using i128 = __int128;
using ldb = long double;
#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
using vii = vector<pii>;
const int inf = 1e9, INF = 1e18;
const int mod = 998244353;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
map<int,int> f;
int calc( int n ){
if( f.count(n) ) return f[n];
int x = n / 2 , y = n - x;
return f[n] = n + calc(x) + calc(y);
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
f[1] = 0;
cout << calc( n );
return 0;
}
D - Super Takahashi Bros.
根据题目描述可以一张有向图,每次根据读入的\(a,b,x\)可以得到\((i,i+1,a),(i,x,b)\)两条边,因此求一下最短路即可。
#include<bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using i128 = __int128;
using ldb = long double;
#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
const int inf = 1e9, INF = 1e18;
const int mod = 998244353;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
vector<vector<pii>> e(n + 1);
for (int i = 1, a, b, x; i < n; i++) {
cin >> a >> b >> x;
e[i].emplace_back(i + 1, a);
e[i].emplace_back(x, b);
}
vi dis(n + 1, INF);
dis[1] = 0;
priority_queue<pii, vector<pii>, greater<pii>> q;
q.emplace(0, 1);
vi vis(n + 1);
for (; not q.empty();) {
auto [d, x] = q.top();
q.pop();
if (vis[x]) continue;
vis[x] = 1;
for (auto [y, w]: e[x]) {
if (vis[y]) continue;
if (d + w >= dis[y]) continue;
dis[y] = d + w;
q.emplace(dis[y], y);
}
}
cout << dis[n] << "\n";
return 0;
}
E - Mancala 2
这道题目实际上要实现的是一个区间修改,单点查询的数据数据结构。我们要注意的是放球的时候不能暴力的放,要计算出整体放球数量以及哪些区间额外的放了一个球
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using i128 = __int128;
using ldb = long double;
#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
using vii = vector<pii>;
const int inf = INT_MAX, INF = 1e18;
const int mod = 998244353;
struct Node {
int l, r, value, add;
Node *left, *right;
Node(int l, int r, int value, int add, Node *left, Node *right) :
l(l), r(r), value(value), add(add), left(left), right(right) {};
} *root;
vi a;
Node *build(int l, int r) {
if (l == r) return new Node(l, r, a[l], 0, nullptr, nullptr);
int mid = (l + r) >> 1;
Node *left = build(l, mid), *right = build(mid + 1, r);
return new Node(l, r, left->value + right->value, 0, left, right);
}
void mark(int v, Node *cur) {
cur->add += v;
cur->value += v * (cur->r - cur->l + 1);
}
void pushdown(Node *cur) {
if (cur->add == 0) return;
mark(cur->add, cur->left), mark(cur->add, cur->right);
cur->add = 0;
}
void modify(int l, int r, int v, Node *cur) {
if (l > cur->r || r < cur->l) return;
if (l <= cur->l && r >= cur->r) {
mark(v, cur);
return;
}
pushdown(cur);
int mid = (cur->l + cur->r) >> 1;
if (l <= mid) modify(l, r, v, cur->left);
if (r > mid) modify(l, r, v, cur->right);
cur->value = cur->left->value + cur->right->value;
return;
}
int query(int l, int r, Node *cur) {
if (l <= cur->l && r >= cur->r) return cur->value;
pushdown(cur);
int mid = (cur->l + cur->r) >> 1, res = 0;
if (l <= mid) res += query(l, r, cur->left);
if (r > mid) res += query(l, r, cur->right);
return res;
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, m;
cin >> n >> m;
a.resize(n);
for (auto &i: a) cin >> i;
root = build(0, n - 1);
for (int b, x, y; m; m--) {
cin >> b;
x = query(b, b, root);
modify(b, b, -x, root);
y = x / n, x %= n;
if (y > 0) modify(0, n - 1, y, root);
if (b + x < n) modify(b + 1, b + x, 1, root);
else {
modify(b + 1, n - 1, 1, root);
modify(0, (b + x) % n, 1, root);
}
}
for (int i = 0; i < n; i++)
cout << query(i, i, root) << " ";
cout << "\n";
return 0;
}
F - S = 1
首先根据向量外积计算三角形面积的公式可以得出\(\frac 12 |Bx-Ay|=1\)
因为这里允许范围包含负数,所以上市有解这一定有\(Bx-Ay=2\)有解。
因此我们要解出这个方程的任意整数解即可,这里就是套用扩展欧几里得的板子即可。
但是要注意的是如果\(A,B\)其中有任意值为零的情况,则解的三角形的一定是短边1长边2的直角三角形,要特判这种情况是否存在。
#include<bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using i128 = __int128;
using ldb = long double;
#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
using vii = vector<pii>;
const int inf = 1e9, INF = 1e18;
const int mod = 998244353;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
int exgcd(int a, int b, int &x, int &y) {
if (b == 0) {
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b, x, y);
int z = x;
x = y, y = z - y * (a / b);
return d;
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int a, b, d, x, y;
cin >> a >> b;
if (a == 0) {
b = abs(b);
if (b <= 2) cout << 2 / b << " 0\n";
else cout << "-1\n";
return 0;
} else if (b == 0) {
a = abs(a);
if (a <= 2) cout << "0 " << 2 / a << "\n";
else cout << "-1\n";
return 0;
}
d = exgcd(b, -a, x, y);
if (2 % d == 0) {
x *= 2 / d, y *= 2 / d;
cout << x << " " << y << "\n";
} else cout << "-1\n";
return 0;
}