AtCoder Beginner Contest 178
Problem A - Not
直接输出,时间复杂度。
Code (Python 3)
x = int(input())
print(1 - x)
Problem B - Product Max
一眼看下去,似乎有很多种情况,但实际上需要考虑的只有端点,也就是。
时间复杂度。
Code (Python 3)
a, b, c, d = map(int, input().split())
x = [a * c, a * d, b * c, b * d]
print(max(x))
Problem C - Ubiquity
简单的容斥原理。
所以最后的答案是。
时间复杂度为。
Code (Python 3)
mod = 1000000007
def fexp(x, y):
ans = 1
while y > 0:
if y % 2 == 1:
ans = ans * x % mod
x = x * x % mod
y //= 2
return ans
n = int(input())
ans = fexp(10, n) - 2 * fexp(9, n) + fexp(8, n)
ans %= mod
if ans < 0:
ans += mod
print(ans)
Problem D - Redistribution
枚举分成多少个数。
假设分成个数,我们首先从中去掉,这样所有的数只要大于等于就可以了。接下来就可以用插板法解决,一共个空,要插入个板子,方法数就是 。
时间复杂度为,如果我们不考虑预计算阶乘及阶乘的逆元的时间代价的话。
Code (Python 3)
mod = 1000000007
def fexp(x, y):
ans = 1
while y > 0:
if y % 2 == 1:
ans = ans * x % mod
x = x * x % mod
y //= 2
return ans
fac = [1]
rev = [1]
for i in range(1, 2006):
fac.append(fac[-1] * i % mod)
rev.append(fexp(fac[-1], mod - 2))
def C(n, k):
if n < k:
return 0
return fac[n] * rev[k] % mod * rev[n - k] % mod
def distribute(n, m):
return C(n - 1, m - 1)
n = int(input())
if n < 3:
print(0)
else:
ans = 0
parts = 1
while n - parts * 2 >= 0:
rest = n - parts * 2
ans += distribute(rest, parts)
ans %= mod
parts += 1
print(ans)
Problem E - Dist Max
这道题目网上很容易能搜索到,但更重要的是理解这一类问题的本质。
我们的目标是求取。暴力穷举需要 的时间,显然会超时。
关键点是把绝对值符号进行展开。我们需要知道,绝对值。
所以在本题中
我们将每一项重新组合,把相同下标的项组合到一起
接下来就能得到
通过记录每种形式的最大值和最小值,我们可以在 内求得答案。
如果你在比赛中参考了网上的解析,这没有什么问题。但更重要的是理解原理。 这一简单的表达式,可以在很多问题中发挥大作用。
Code (C++)
#include <iostream>
#include <vector>
using namespace std;
typedef long long ll;
const int d[4][2] = {{1, 1}, {1, -1}, {-1, 1}, {-1, -1}};
int main() {
int n;
cin >> n;
vector<ll> lo(4, 1e12), hi(4, -1e12);
for (int i = 0; i < n; ++i) {
ll x, y;
cin >> x >> y;
for (int k = 0; k < 4; ++k) {
ll result = x * d[k][0] + y * d[k][1];
lo[k] = min(lo[k], result);
hi[k] = max(hi[k], result);
}
}
ll ans = 0;
for (int k = 0; k < 4; ++k)
ans = max(ans, hi[k] - lo[k]);
cout << ans;
}
Problem F - Contrast
这题和CF1381C - Mastermind很像。
首先我们找出所有的冲突数,也即两个序列共有的数。我们把它们按照数值分组,然后用一个大根堆存储。每次,我们取出最上面两组,从中各取出一个位置,然后交叉放置,也即;唯一的例外情况是只剩三组,且每组只有一个位置,此时我们采用轮换的方式,也即。
在此之后,最多只剩一种冲突数。我们首先考虑这个数(注意,不能只考虑冲突的部分,而要考虑所有部分。考虑这个例子:,只有一对冲突的,但我们必须同时考虑第二个序列中的两个),尝试将它们都放入合法的位置。
如果这一步不能完成,说明无解。
在此之后,所有剩下的数都不会引发冲突,我们只要按次序放入空位即可。
Code (C++)
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> a(n), b(n), cb(n + 1);
vector<bool> taken(n);
vector<vector<int>> ca(n + 1);
for (int i = 0; i < n; ++i) {
cin >> a[i];
ca[a[i]].emplace_back(i);
}
for (int i = 0; i < n; ++i) {
cin >> b[i];
cb[b[i]]++;
}
priority_queue<pair<int, int>> pq;
for (int i = 1; i <= n; ++i) {
int lo = min((int)ca[i].size(), cb[i]);
if (lo)
pq.emplace(lo, i);
}
while (pq.size() >= 2) {
auto [cx, x] = pq.top();
pq.pop();
auto [cy, y] = pq.top();
pq.pop();
if (cx == 1 && pq.size() == 1) {
auto [cz, z] = pq.top();
pq.pop();
int px = ca[x].back();
int py = ca[y].back();
int pz = ca[z].back();
taken[px] = taken[py] = taken[pz] = true;
b[px] = y;
b[py] = z;
b[pz] = x;
ca[x].pop_back();
ca[y].pop_back();
ca[z].pop_back();
cb[x]--;
cb[y]--;
cb[z]--;
} else {
int px = ca[x].back();
int py = ca[y].back();
taken[px] = taken[py] = true;
b[px] = y;
b[py] = x;
ca[x].pop_back();
ca[y].pop_back();
cb[x]--;
cb[y]--;
if (cx > 1)
pq.emplace(cx - 1, x);
if (cy > 1)
pq.emplace(cy - 1, y);
}
}
int idx = 0;
if (!pq.empty()) {
auto [cx, x] = pq.top();
pq.pop();
while (cb[x]) {
while (idx < n && (taken[idx] || a[idx] == x))
idx++;
if (idx >= n)
break;
b[idx] = x;
cb[x]--;
taken[idx] = true;
}
if (cb[x]) {
cout << "No" << flush;
return 0;
}
}
vector<int> rest;
for (int i = 1; i <= n; ++i)
if (cb[i]) {
for (int j = 0; j < cb[i]; ++j)
rest.emplace_back(i);
}
idx = 0;
for (int i : rest) {
while (taken[idx])
idx++;
b[idx] = i;
taken[idx] = true;
}
cout << "Yes" << endl;
for (int i : b)
cout << i << " ";
cout << flush;
}