比赛链接:https://atcoder.jp/contests/abc169/tasks
A - Multiplication 1
#include <bits/stdc++.h> using namespace std; int main() { int a, b; cin >> a >> b; cout << a * b << " "; }
B - Multiplication 2
题意
计算 $a_1 imes a_2 imes ... imes a_n$ 。($2≤n≤10^5, 0≤ a_i ≤ 10^{18}$)
题解一
若 $ans$ 乘以某个 $a_i$ 大于 $10^{18}$ 则溢出,即:
$ans imes a_i > 10^{18}$,
为避免运算过程中乘积溢出,移项得:$a_i > frac{10^{18}}{ans}$ 。
代码
#include <bits/stdc++.h> using ll = long long; using namespace std; const ll MAXN = 1e18; int main() { int n; cin >> n; ll a[n] = {}; for (int i = 0; i < n; i++) cin >> a[i]; if (count(a, a + n, 0)) { cout << 0 << " "; return 0; } ll ans = 1; for (int i = 0; i < n; i++) { if (a[i] > MAXN / ans) { cout << -1 << " "; return 0; } ans *= a[i]; } cout << ans << " "; }
题解二
转化为 __int128 可以避免溢出。
代码
#include <bits/stdc++.h> using ll = long long; using namespace std; const ll MAXN = 1e18; int main() { int n; cin >> n; ll a[n] = {}; for (int i = 0; i < n; i++) cin >> a[i]; if (count(a, a + n, 0)) { cout << 0 << " "; return 0; } ll ans = 1; for (int i = 0; i < n; i++) { if ((__int128)ans * a[i] > MAXN) { cout << -1 << " "; return 0; } ans *= a[i]; } cout << ans << " "; }
题解三
如果能由下一个积除以 $a_i$ 得到现在的积说明不会发生溢出,但是这个方法需要用 $unsigned long long$ 才行。
代码
#include <bits/stdc++.h> using ull = unsigned long long; using namespace std; const ull MAXN = 1e18; int main() { int n; cin >> n; ull a[n] = {}; for (int i = 0; i < n; i++) cin >> a[i]; if (count(a, a + n, 0)) { cout << 0 << " "; return 0; } ull ans = 1; for (int i = 0; i < n; i++) { ull next = ans * a[i]; if (next / a[i] != ans or next > MAXN) { cout << -1 << " "; return 0; } ans *= a[i]; } cout << ans << " "; }
题解四
使用 python 中自带的大数运算。
代码
def main(): N = int(input()) A = list(map(int, input().split())) if 0 in A: print(0) return ans = 1 for a in A: ans *= a if ans > int(1e18): print(-1) return print(ans) main()
C - Multiplication 3
题意
$a$ 为整数,$b$ 为保留小数点后两位的小数,计算 $a imes b$ 。($0≤a≤10^{15}, 0≤ b < 10$)
题解
把 $b$ 转化为整数再计算。
代码
#include <bits/stdc++.h> using ll = long long; using namespace std; int main() { ll a; string s; cin >> a >> s; s.erase(1, 1); ll b = stoll(s); cout << a * b / 100; }
D - Div Game
题意
给出一个正整数 $n$,每次操作可以选择一个正整数 $z$,要求:
- $z = p^e$,$p$ 为正素数,$e$ 为正数
- $z$ 整除 $n$
- $z$ 不同于任一之前选择的 $z$
- 如果以上条件满足,$n = frac{n}{z}$
找出最多可以进行多少次操作。
题解
找出每个质因数的个数,依次减去 $1,2,3...$ 即可。
代码
#include <bits/stdc++.h> using ll = long long; using namespace std; int main() { ll n; cin >> n; map<ll, ll> mp; for (ll i = 2; i * i <= n; i++) { while (n % i == 0) { ++mp[i]; n /= i; } } if (n != 1) ++mp[n]; ll ans = 0; for (auto i : mp) { for (int j = 1; j <= i.second; j++) { i.second -= j; ++ans; } } cout << ans << " "; }
E - Count Median
题意
有 $n$ 个数 $x_1,x_2,...,x_n$,$a_i≤x_i≤b_i$,找出中值 $x_{mid}$ 可能的值的个数。
- 中值为将所有 $x_i$ 排序,位于中间的 $x_i$
- 如果 $n$ 为奇数,中值为 $x_{(n+1)/2}$
- 如果 $n$ 为偶数,中值为 $(x_{n/2} + x_{n/2 + 1}) / 2$
题解
中值的最小值为 $a_i$ 的中值,最大值为 $b_i$ 的中值,中值的个数即:$b_{mid} - a_{mid} + 1$ 。
代码
#include <bits/stdc++.h> using namespace std; int main() { int n; cin >> n; int a[n] = {}, b[n] = {}; for (int i = 0; i < n; i++) cin >> a[i] >> b[i]; sort(a, a + n); sort(b, b + n); int mi = 0, mx = 0; if (n & 1) { mi = a[n / 2]; mx = b[n / 2]; } else { mi = a[n / 2 - 1] + a[n / 2]; mx = b[n / 2 - 1] + b[n / 2]; } cout << mx - mi + 1; }
F - Knapsack for All Subsets
题意
有 $n$ 个数 $a_1,a_2,...,a_n$,计算 ${1,2,...,n}$ 的 $2^n - 1$ 个非空子集有多少子集作为下标求和可以得到 $s$ 。
题解
$dp_i$ 表示和为 $i$ 的集合共有多少个。
每次添加一个数 $x$,会产生两种变化:
- $x$ 与 $dp_i$ 中的每个集合构成的新集合都可以构成 $i + x$:$dp_{i + x} += dp_i$
- $x$ 与 $dp_i$ 中的每个集合构成了一个包含原先集合的新集合:$dp_i *= 2$
代码
#include <bits/stdc++.h> using namespace std; const int mod = 998244353; int dp[6010]; int main() { int n, s; cin >> n >> s; dp[0] = 1; for (int i = 0; i < n; i++) { int x; cin >> x; for (int j = s; j >= 0; j--) { (dp[j + x] += dp[j]) %= mod; (dp[j] *= 2) %= mod; } } cout << dp[s] << " "; }