ABC392题解
A
算法标签: 模拟
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int w[3];
for (int i = 0; i < 3; ++i) cin >> w[i];
sort(w, w + 3);
if (w[0] * w[1] == w[2]) cout << "Yes" << "\n";
else cout << "No";
return 0;
}
B
算法标签: 哈希表
#include <iostream>
#include <algorithm>
#include <cstring>
#include <unordered_set>
#include <vector>
using namespace std;
const int N = 1010;
int range, n, w[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
unordered_set<int> s;
cin >> range >> n;
for (int i = 0; i < n; ++i) {
int val;
cin >> val;
s.insert(val);
}
vector<int> res;
for (int i = 1; i <= range; ++i) {
if (!s.count(i)) res.push_back(i);
}
cout << res.size() << "\n";
for (int val : res) cout << val << " ";
cout << "\n";
return 0;
}
C
算法标签: 模拟
#include <iostream>
#include <algorithm>
#include <cstring>
#include <unordered_set>
#include <vector>
using namespace std;
const int N = 3e5 + 10;
int n;
int p[N], q[N];
int pos[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 1; i <= n; ++i) cin >> p[i];
for (int i = 1; i <= n; ++i) {
cin >> q[i];
pos[q[i]] = i;
}
for (int i = 1; i <= n; ++i) {
int per = pos[i];
int see = p[per];
cout << q[see] << " ";
}
cout << "\n";
return 0;
}
D
算法标签: 桶计数, 模拟
*精度不够的错误案例
而且没说两个骰子只有一个点数相等, 下面做法有遗漏情况
#include <iostream>
#include <algorithm>
#include <cstring>
#include <unordered_set>
#include <vector>
using namespace std;
const int N = 110, M = 1e5 + 10;
const double EPS = 1e-20;
int n;
int cnt[N];
// 记录每个骰子 每个数字出现的概率
double w[N][M];
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> cnt[i];
for (int j = 1; j <= cnt[i]; ++j) {
int val;
cin >> val;
w[i][val] += 1.0 / cnt[i];
}
}
// 枚举点数
double res = 0;
for (int i = 1; i < M; ++i) {
vector<double> nums;
for (int j = 1; j <= n; ++j) {
if (w[j][i] > EPS) nums.push_back(w[j][i]);
}
sort(nums.begin(), nums.end(), greater<double>());
if (nums.size() < 2) continue;
double tmp = nums[0] * nums[1];
res = max(res, tmp);
}
printf("%lf\n", res);
return 0;
}
正确解法
#include <iostream>
#include <algorithm>
#include <cstring>
#include <unordered_set>
#include <vector>
using namespace std;
typedef long double LD;
const int N = 110, M = 1e5 + 10;
const double EPS = 1e-20;
int n;
int cnt[N];
int w[N][M];
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> cnt[i];
for (int j = 1; j <= cnt[i]; ++j) {
int val;
cin >> val;
w[i][val]++;
}
}
LD res = 0;
for (int i = 1; i < n; ++i) {
for (int j = i + 1; j <= n; ++j) {
LD curr = 0;
for (int k = 1; k < M; ++k) {
curr +=( (LD) w[i][k] / cnt[i]) * ((LD) w[j][k] / cnt[j]);
}
res = max(res, curr);
}
}
printf("%.15Lf\n", res);
return 0;
}
E
算法标签: D S U DSU DSU, 并查集
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
typedef pair<int, int> PII;
const int N = 2e5 + 10, M = 4e5 + 10;
int n, m;
int p[N];
int vers[M];
bool vis[M];
int find(int u) {
if (p[u] != u) p[u] = find(p[u]);
return p[u];
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; ++i) p[i] = i;
for (int i = 1; i <= m; ++i) {
int u, v;
cin >> u >> v;
int fa1 = find(u);
int fa2 = find(v);
if (fa1 != fa2) p[fa2] = fa1;
else {
vis[i] = true;
vers[i] = u;
}
}
int res = 0;
for (int i = 1; i <= n; ++i) {
if (p[i] == i) res++;
}
cout << res - 1 << "\n";
int k = 1;
for (int i = 1; i <= n; ++i) {
if (!vis[i]) continue;
while (k <= n && find(k) == find(vers[i])) k++;
if (k > n) break;
int fa1 = find(k);
int fa2 = find(vers[i]);
p[fa1] = fa2;
cout << i << " " << vers[i] << " " << k << "\n";
}
return 0;
}
F
算法标签: 树状数组, F e n w i c k − T r e e Fenwick-Tree Fenwick−Tree, B S T BST BST
思路
如果正着做, 插入不好操作, 平衡树操作, 如果倒着做, 插入第 n n n个数, 所在位置 p n − 1 p_{n - 1} pn−1, 初始化树状数组每个位置 1 1 1, 如果这个位置被占用将其改为 0 0 0, 寻找从左往右的第 p n − 1 p_{n - 1} pn−1个空格, 也就是找 p n − 1 p_{n - 1} pn−1就是找前缀和等于 p n − 1 p_{n - 1} pn−1的位置, 时间复杂度 O ( n log 2 n ) O(n\log ^ 2n) O(nlog2n)
树状数组写法
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 5e5 + 10;
int n, w[N];
int tr[N], res[N];
int lowbit(int val) {
return val & -val;
}
void add(int u, int val) {
for (int i = u; i <= n; i += lowbit(i)) tr[i] += val;
}
int query(int u) {
int res = 0;
for (int i = u; i; i -= lowbit(i)) res += tr[i];
return res;
}
int find(int val) {
int l = 1, r = n;
while (l < r) {
int mid = l + r >> 1;
if (query(mid) >= val) r = mid;
else l = mid + 1;
}
return l;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 1; i <= n; ++i) cin >> w[i];
for (int i = 1; i <= n; ++i) add(i, 1);
for (int i = n; i >= 1; --i) {
int pos = find(w[i]);
res[pos] = i;
add(pos, -1);
}
for (int i = 1; i <= n; ++i) cout << res[i] << " ";
cout << "\n";
return 0;
}
线段树写法
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 5e5 + 10;
int n, w[N];
struct Node {
int l, r;
int sum;
} tr[N << 2];
int res[N];
void push_up(int u) {
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}
void build(int u, int l, int r) {
if (l == r) {
tr[u] = {l, r, 1};
return;
}
tr[u] = {l, r};
int mid = l + r >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
push_up(u);
}
void update(int u, int pos, int val) {
if (tr[u].l == tr[u].r) {
tr[u].sum += val;
return;
}
int mid = tr[u].l + tr[u].r >> 1;
if (pos <= mid) update(u << 1, pos, val);
if (pos > mid) update(u << 1 | 1, pos, val);
push_up(u);
}
// 查询和为val的起始位置
int query(int u, int k) {
if (tr[u].l == tr[u].r) return tr[u].l;
if (tr[u << 1].sum < k) return query(u << 1 | 1, k - tr[u << 1].sum);
else return query(u << 1, k);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 1; i <= n; ++i) cin >> w[i];
build(1, 1, n);
for (int i = n; i >= 1; --i) {
// 找到第w[i]个未被赋值的位置
int pos = query(1, w[i]);
res[pos] = i;
update(1, pos, -1);
}
for (int i = 1; i <= n; ++i) cout << res[i] << " ";
cout << "\n";
return 0;
}