ABC350 A-E题解
- A
- 题目
- AC Code(CPP):
- AC Code(Python):
- B
- 题目
- AC Code(CPP):
- AC Code(Python):
- C
- 题目
- AC Code(CPP):
- AC Code(Python)
- D
- 题目
- AC Code(CPP):
- AC Code(Python):
- E
- 题目
- 时间复杂度分析
- AC Code(CPP):
- AC Code(Python):
- F
- 题目
- AC Code(CPP):
- AC Code(Python):
下面的内容不包括题目翻译,要想获取题目翻译,请参照 这篇教程 来获取题目翻译。
A
题目
只需要判断 S S S 是否在 ABC001
到 ABC349
范围内即可。
可以使用字符串之间的大小关系来快速通过此题。
AC Code(CPP):
#include <iostream>
using namespace std;
string s;
string t = "ABC350";int main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> s;if (s < t && s != "ABC316" && s >= "ABC001") {cout << "Yes";}else {cout << "No";}return 0;
}
AC Code(Python):
s = input()
print(('No', 'Yes')[s != 'ABC316' and 'ABC001' <= s <= 'ABC349'])
B
题目
在 C++
中,可以通过使用一个布尔数组来判断这颗牙齿是否被拔除。而在 Python
中,可以通过集合实现。如果集合里面有这个元素,说明这颗牙齿被拔掉了,否则,说明这颗牙齿还在。
AC Code(CPP):
#include <iostream>
using namespace std;
int n, q;
bool vis[2010];int main() {cin >> n >> q;while (q--) {int t;cin >> t;if (vis[t]) {n++;vis[t] = 0;}else {n--;vis[t] = 1;}}cout << n << '\n';return 0;
}
AC Code(Python):
n, q = [int(i)for i in input().split()]
a = set([])
t = [int(i)for i in input().split()]for k in t:if k in a:n += 1a.remove(k)else:n -= 1a.add(k)print(n)
C
题目
答案的特性: i = a i i=a_i i=ai。根据这个特性,我们可以对于不在对应位置上的每一个数,让正确的数和它交换。由于数一共只有 N N N 个,交换最多 N − 1 N-1 N−1 次,所以可以符合条件。
注意 python
的下标问题。
AC Code(CPP):
#include <iostream>
#include <queue>
using namespace std;
int n;
int a[200100];
int p = -1;
int idx[200100];
queue<pair<int, int>> q;int main() {cin >> n;for (int i = 1; i <= n; i++) cin >> a[i];for (int i = 1; i <= n; i++) {idx[a[i]] = i;}int cnt = 0;for (int i = 1; i <= n; i++) {if (a[i] != i) {cnt++;q.push({min(idx[i], i), max(idx[i], i)});int tmp = idx[i];swap(idx[a[i]], idx[i]);swap(a[i], a[tmp]);}}cout << cnt << '\n';while (!q.empty()) {cout << q.front().first << ' ' << q.front().second << '\n';q.pop();}return 0;
}
AC Code(Python)
n = int(input())
a = [int(i) - 1 for i in input().split()]
idx = [0 for i in range(n)]
for i in range(n):idx[a[i]] = i
ans = []
for i in range(n):if a[i] != i:ans.append([min(idx[i], i), max(idx[i], i)])temp = idx[i]idx[a[i]], idx[i] = idx[i], idx[a[i]]a[i], a[temp] = a[temp], a[i]
print(len(ans))
for i in ans:print('%d %d' % (i[0] + 1, i[1] + 1))
D
题目
这个问题须要一点图论知识。
我们可以发现,对于一群人,如果这群人是“联通”的,那么就一定可以将这一群人操作成一个“完全图”。所以对于一群联通的人,操作次数就等于这张图成为完全图的边数(点数乘以点数减一)减去已有的朋友关系。
通过并查集来查找联通块,并快速地解决这个问题。
注意 Python
中递归层数的限制
AC Code(CPP):
#include <iostream>
#define int long long
using namespace std;
int n, m;
int u[200100], v[200100];
int f[200100];
long long cnt[200100], cnt1[200100];
int find(int x) {return x == f[x] ? x : f[x] = find(f[x]);}
bool vis[200100];
long long ans;signed main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n >> m;for (int i = 1; i <= n; i++) f[i] = i;for (int i = 1; i <= m; i++) {cin >> u[i] >> v[i];f[find(v[i])] = find(u[i]);}for (int i = 1; i <= m; i++) {cnt[find(u[i])]++;}for (int i = 1; i <= n; i++) {cnt1[find(i)]++;}for (int i = 1; i <= n; i++) {if (find(i) == i)ans += cnt1[i] * (cnt1[i] - 1ll) / 2ll - cnt[i];}cout << ans << '\n';return 0;
}
AC Code(Python):
import sys
sys.setrecursionlimit(998244353)
n, m = [int(i) for i in input().split()]
f = [i for i in range(n + 3)]def find(x):if x != f[x]:f[x] = find(f[x])return f[x]a = []
for i in range(m):a.append([int(i) for i in input().split()])a[i][1] -= 1a[i][0] -= 1f[find(a[i][1])] = find(a[i][0])
cnt = [0] * (n + 3)
cnt1 = [0] * (n + 3)
for i in range(m):cnt[find(a[i][0])] += 1
for i in range(n):cnt1[find(i)] += 1
ans = 0
for i in range(n):if find(i) == i:ans += (cnt1[i] * (cnt1[i] - 1) // 2) - cnt[i]
print(ans)
E
题目
可以想到使用搜索加上记忆化来解决这个问题。设 f ( x ) f(x) f(x) 是把 x x x 变为 0 0 0 的代价,这个值为操作一期望代价和操作二期望代价的最小值,其中操作一期望代价很好算,就是 f ( ⌊ x A ⌋ ) + X f(\lfloor \frac{x}{A} \rfloor) + X f(⌊Ax⌋)+X。而操作二期望代价是这个式子:
f ( x ) = 1 6 f ( ⌊ 1 x ⌋ ) + 1 6 f ( ⌊ x 2 ⌋ ) + 1 6 f ( ⌊ x 3 ⌋ ) + 1 6 f ( ⌊ x 4 ⌋ ) + 1 6 f ( ⌊ x 5 ⌋ ) + 1 6 f ( ⌊ x 6 ⌋ ) + Y f(x)=\frac16f(\lfloor \frac1x \rfloor) + \frac16f(\lfloor \frac x2 \rfloor) + \frac16f(\lfloor \frac x3 \rfloor) + \frac16f(\lfloor \frac x4 \rfloor) + \frac16f(\lfloor \frac x5 \rfloor) + \frac16f(\lfloor \frac x6 \rfloor)+Y f(x)=61f(⌊x1⌋)+61f(⌊2x⌋)+61f(⌊3x⌋)+61f(⌊4x⌋)+61f(⌊5x⌋)+61f(⌊6x⌋)+Y
这个式子看似要无线递归,但是通过移项可以得到这个东西:
f ( x ) = f ( ⌊ x 2 ⌋ ) + f ( ⌊ x 3 ⌋ ) + f ( ⌊ x 4 ⌋ ) + f ( ⌊ x 5 ⌋ ) + f ( ⌊ x 6 ⌋ ) + Y 5 f(x)=\frac{f(\lfloor \frac x2 \rfloor) + f(\lfloor \frac x3 \rfloor) + f(\lfloor \frac x4 \rfloor) + f(\lfloor \frac x5 \rfloor) + f(\lfloor \frac x6 \rfloor)+Y}5 f(x)=5f(⌊2x⌋)+f(⌊3x⌋)+f(⌊4x⌋)+f(⌊5x⌋)+f(⌊6x⌋)+Y
编码就十分简单。
时间复杂度分析
首先,枚举第一种情况是 log A ( N ) \log_A(N) logA(N) 的时间复杂度,可以视为没有。
第二种情况:
由于 ⌊ ⌊ N a ⌋ b ⌋ = ⌊ N a b ⌋ \lfloor\frac{\lfloor \frac Na \rfloor}b\rfloor=\lfloor \frac N{ab}\rfloor ⌊b⌊aN⌋⌋=⌊abN⌋,所以讨论 4 4 4, 6 6 6 的情况会被 2 2 2 和 3 3 3 剪枝。而我们要计算的是 ⌊ N m ⌋ \lfloor \frac Nm\rfloor ⌊mN⌋,所以 m m m 可以被表示为 2 x 3 y 5 z 2^x3^y5^z 2x3y5z,而时间复杂度也只有 log 2 ( N ) log 3 ( N ) log 4 ( N ) \log_2(N)\log_3(N)\log_4(N) log2(N)log3(N)log4(N)。
AC Code(CPP):
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n, a, x, y;
map<long long, double> m;
double f(int now) {if (now == 0) return 0;if (m[now]) return m[now];double sum = y;for (int i = 2; i <= 6; i++) {sum += f(now / i) + y;}m[now] = min({sum / 5.0, f(now / a) + x});return min({sum / 5.0, f(now / a) + x});
}
signed main() {scanf("%lld%lld%lld%lld", &n, &a, &x, &y);printf("%.16lf", f(n));return 0;
}
AC Code(Python):
n, a, x, y = [int(i)for i in input().split()]
m = {}def f(now):if now == 0:return 0if now in m.keys():return m[now]cnt = yfor i in range(2, 7):cnt += f(now // i) + ym[now] = min(cnt / 5, f(now // a) + x)return m[now]print(f(n))
F
题目
可以通过递归函数计算。 f ( l , r , p ) f(l, r, p) f(l,r,p) 负责打印从 l l l 到 r r r 的字符。如果 p p p 等于 0 0 0,那么是正序打印,否则,是倒序打印。每遇到一个括号,就打印括号内的东西,打印顺序反过来。每一对对应的括号可以通过预处理得到。可以预先将每一个大小写预处理,就不用再打印时判断了。(如果括号层数为奇数就要翻转大小写。)或者在打印时判断。
于是可以在 O ∣ S ∣ O|S| O∣S∣ 的时间复杂度内求解问题。
AC Code(CPP):
#include <iostream>
#include <cstring>
#include <stack>
using namespace std;
char s[500100];
int n;
void init() {string s1;cin >> s1;for (int i = 0; i < (int)s1.size(); i++) {s[i + 1] = s1[i];}n = s1.size();
}
int idx[500100], idx1[500100];void f(int l, int r, int p) {if (p == 0) {for (int i = l; i <= r; i++) {if (s[i] == '(') {f(i + 1, idx[i] - 1, 1);i = idx[i];}else {cout << s[i];}}}else {for (int i = r; i >= l; i--) {if (s[i] == ')') {f(idx1[i] + 1, i - 1, 0);i = idx1[i];}else {cout << s[i];}}}
}
int main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);init();int cnt = 0;stack<int> st;for (int i = 1; i <= n; i++) {if (s[i] == '(') {cnt++;st.push(i);}else if (s[i] == ')') {cnt--;idx[st.top()] = i;idx1[i] = st.top();st.pop();}else {if (cnt % 2) {if ('a' <= s[i] && s[i] <= 'z') {s[i] -= 'a';s[i] += 'A';}else {s[i] -= 'A';s[i] += 'a';}}}}f(1, n, 0);return 0;
}
AC Code(Python):
import sys
sys.setrecursionlimit(998244353)
s = input()
cnt = 0
idx = [0] * (len(s) + 1)
idx1 = [0] * (len(s) + 1)
stack = []def f(l, r, p):if p == 0:temp = lwhile temp <= r:if s[temp] == '(':f(temp + 1, idx[temp] - 1, 1)temp = idx[temp] + 1else:print(s[temp], end='')temp += 1else:temp = rwhile temp >= l:if s[temp] == ')':f(idx1[temp] + 1, temp - 1, 0)temp = idx1[temp] - 1else:if 'a' <= s[temp] <= 'z':print(chr(ord(s[temp]) - 32), end='')else:print(chr(ord(s[temp]) + 32), end='')temp -= 1for i in range(len(s)):if s[i] == '(':cnt += 1stack.append(i)elif s[i] == ')':cnt -= 1idx[stack[len(stack) - 1]] = iidx1[i] = stack[len(stack) - 1]stack.pop(len(stack) - 1)
f(0, len(s) - 1, 0)