Atcoder Beginner Contest 448
比赛链接:Atcoder Beginner Contest 448
A. chmin
按照题意模拟即可。
时间复杂度: \(O(N)\)。
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n, x;
cin >> n >> x;
for (int i = 0; i < n; i++)
{
int a;
cin >> a;
if (a < x)
{
cout << 1 << "\n";
x = a;
}
else
cout << 0 << "\n";
}
return 0;
}
B. Pepper Addiction
尽量将每一个位置都填充到上限 \(B\),填充完统计最后结果。
时间复杂度: \(O(N)\)。
#include <bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n, m, ans = 0;
cin >> n >> m;
vector<int> c(m);
for (int i = 0; i < m; i++)
cin >> c[i];
for (int i = 1; i <= n; i++)
{
int a, b;
cin >> a >> b;
int res = min(c[a - 1], b);
c[a - 1] -= res, ans += res;
}
cout << ans << "\n";
return 0;
}
C. Except and Min
用 multiset 维护当前的数列,每一次查询将要删除的数从 multiset 中删除,输出当前 multiset 中的最小值,再将被删除的数重新插入 multiset 中。
时间复杂度: \(O(N\log N + \sum K \log N)\)
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 5, K = 10;
int n, q, k, a[N], b[K];
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n >> q;
multiset<int> ms;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
ms.insert(a[i]);
}
while (q--)
{
cin >> k;
for (int i = 1; i <= k; i++)
{
cin >> b[i];
auto it = ms.find(a[b[i]]);
if (it != ms.end())
ms.erase(it);
}
cout << *ms.begin() << "\n";
for (int i = 1; i <= k; i++)
ms.insert(a[b[i]]);
}
return 0;
}
D. Integer-duplicated Path
从节点 \(1\) 开始进行 DFS,利用 unordered_map 记录路径上所有节点的值的出现个数,根据前面路径节点值出现的个数判断当前节点的值是否有出现过。
时间复杂度: \(O(N)\)。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int n, head[N], a[N], num = 0;
bool ans[N];
struct edge { int to, nxt; } e[N << 1];
void AddEdge(int u, int v)
{
e[++num] = { v, head[u] };
head[u] = num;
}
void dfs(int u, int fa, unordered_map<int, int>& vis)
{
if (ans[fa] || (vis.find(a[u]) != vis.end() && vis[a[u]] > 0))
ans[u] = true;
vis[a[u]]++;
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to;
if (v == fa)
continue;
dfs(v, u, vis);
}
vis[a[u]]--;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i], ans[i] = false;
for (int i = 1; i < n; i++)
{
int u, v;
cin >> u >> v;
AddEdge(u, v), AddEdge(v, u);
}
unordered_map<int, int> vis;
dfs(1, 0, vis);
for (int i = 1; i <= n; i++)
{
if (ans[i])
cout << "Yes\n";
else
cout << "No\n";
}
return 0;
}
E. Simple Division
假设 \(\left \lfloor \frac{N}{M} \right \rfloor = res\) (\(mod\ 10007\)),那么可以得到 \(N = 10007 \times M \times T + M \times res + b\),其中 \(T\) 是一个非负整数,\(b\) 是 \(0\) 到 \(M-1\) 之间的整数。从而得到 \(\left \lfloor \frac{N}{M} \right \rfloor = \left\lfloor \frac{N \% (10007M)}{M} \right\rfloor\)。
根据题目中的规则,可以发现 \(N = N \times 10^l + \frac{10^l - 1}{9} \times c\),但由于模数 \(10007M\) 不是质数,所以对于 \(\frac{10^l - 1}{9}\) 无法利用费马小定理求乘法逆元。
但原式可以变形为 \(9N = 9N \times 10^l + \frac{10^l - 1}{9} \times c\),我们可以先计算 \(9N\),这个时候的模数就变成了 \(10007M \times 9\)。最后要输出的结果是 \(\left\lfloor \frac{N \% (10007M \times 9)}{M} \right\rfloor\)。
时间复杂度: \(O(K\log l)\)。
#include <bits/stdc++.h>
using namespace std;
#define int long long
int qpow(int x, int k, int mod)
{
int res = 1;
while (k)
{
if (k & 1)
res = res * x % mod;
x = x * x % mod;
k >>= 1;
}
return res;
}
int n, m, k;
signed main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> k >> m;
int mod = 9 * 10007 * m;
for (int i = 1; i <= k; i++)
{
int c, l;
cin >> c >> l;
int pw10 = qpow(10, l, mod);
n = (n * pw10 % mod + (pw10 - 1 + mod) % mod * c % mod) % mod;
}
cout << n / m / 9 << "\n";
return 0;
}
F. Authentic Traveling Salesman Problem
平面范围为 \(X\le 2\times10^7\),点数为 \(N\le6\times10^4\)。如果按普通的 \(x\) 再按 \(y\) 排序,可能会产生大量上下往返,使路径很长。一个常见技巧是 蛇形扫描(Snake Order)。
我们将平面按 \(x\) 坐标分成若干宽度为 \(B\) 的竖条,再进行排序。
排序规则:
- 先按每一个块从小到大排序
- 若在同一块:
- 偶数块:按 \(y\) 升序
- 奇数块:按 \(y\) 降序
这样访问顺序类似:
↑ ↓ ↑ ↓
| | | |
| | | |
路径在相邻块之间会自然连接,减少来回移动。
块大小选择
设块宽为 \(B\),总路径长度可以估计为: \(\frac{X^2}{B} + NB + O(X)\)
当 \(B = \frac{X}{\sqrt N}\) 时,总路径长度最小。
本题中 \(X \le 2e7\), \(N \le 6e4\),因此 \(B \approx 8e4\),可以满足距离限制。
题目要求从 \(1\) 开始出发,因此排序后找到 \(1\) 的位置,再从该位置循环输出即可。
时间复杂度: \(O(N \log N)\)
#include <bits/stdc++.h>
using namespace std;
const int N = 6e4 + 5;
int n, x[N], y[N], p[N];
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n;
int B = 2e7 / sqrt(N);
for (int i = 1; i <= n; i++)
cin >> x[i] >> y[i], p[i] = i;
sort(p + 1, p + n + 1, [&](int l, int r){
if (x[l] / B != x[r] / B)
return x[l] / B < x[r] / B;
if ((x[l] / B) % 2)
return y[l] > y[r];
else
return y[l] < y[r];
});
int pos = 1;
while (p[pos] != 1)
pos++;
for (int i = 0; i < n; i++)
{
int idx = pos + i;
if (idx > n)
idx -= n;
cout << p[idx] << " ";
}
cout << "\n";
return 0;
}

浙公网安备 33010602011771号