AcWing第5场周赛题解
A. AcWing 3726. 调整数组
题目链接:https://www.acwing.com/problem/content/3729/
题目大意:判断若干次 \(+2\) 操作能否最终让所有值都相等。
解题思路:\(n\) 个数奇偶性相同就行。
示例程序:
#include <bits/stdc++.h>
using namespace std;
int T, n, a[101];
bool check() {
for (int i = 1; i < n; i++)
if (a[0]%2 != a[i]%2)
return false;
return true;
}
int main() {
cin >> T;
while (T--) {
cin >> n;
for (int i = 0; i < n; i++) cin >> a[i];
puts(check() ? "YES" : "NO");
}
return 0;
}
B. AcWing 3727. 乘方相加
题目链接:https://www.acwing.com/problem/content/3730/
题目大意:求由 \(k^0, k^1, k^2, \ldots\) 能否加成一个数列 \(a\)。
解题思路:贪心。由于 \(k \ge 2\),则 \(2^0 + 2^1 + 2^2 + \ldots + 2^{k-1} \lt 2^k\),所以我们可以从大到小判断 \(2^k\) 和当前数列中最大的那个数,如果最大的那个数 \(\ge 2^k\),则最大的那个数减去 \(2^k\),这样如果最终能都变成 \(0\),则说明 YES;否则 NO。(实现是使用优先队列即时获得及更新最大的那个数)
示例程序:
#include <bits/stdc++.h>
using namespace std;
int T, n, k;
priority_queue<long long> pq;
long long a;
bool check() {
while (!pq.empty()) pq.pop();
cin >> n >> k;
while (n--) {
cin >> a;
if (a > 0) pq.push(a);
}
long long t = 1;
while (t <= (1LL<<60) / k) t *= k;
for (; t >= 1 && !pq.empty(); t /= k) {
long long u = pq.top();
if (u >= t) {
pq.pop();
u -= t;
if (u > 0) pq.push(u);
}
}
return pq.empty();
}
int main() {
cin >> T;
while (T--) {
puts(check() ? "YES" : "NO");
}
return 0;
}
C. AcWing 3728. 城市通电
题目链接:https://www.acwing.com/problem/content/3731/
题目大意:通过建立发电站和搭建电线的方式给每座城市都通电。求最小花费。
解题思路:最小生成树。思路是额外增加一个超级点 \(s\),\(s\) 向每个点 \(i\) 连一条权值为 \(c_i\) 的边,然后求 MST。
示例程序:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2020;
int n, pre[maxn];
long long g[maxn][maxn], x[maxn], y[maxn], cost[maxn], k[maxn];
bool vis[maxn];
vector<int> v1;
vector<pair<int, int>> v2;
int main() {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++)
cin >> x[i] >> y[i];
for (int i = 1; i <= n; i++)
cin >> g[0][i]; // g[i][0]可以赋值但是我这里用不到
for (int i = 1; i <= n; i++)
cin >> k[i];
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
g[i][j] = (abs(x[i]-x[j]) + abs(y[i]-y[j])) * (k[i] + k[j]);
memset(cost, 0x3f, sizeof(cost));
cost[0] = 0;
long long ans = 0;
for (int i = 0; i <= n; i++) {
int u = -1;
for (int j = 0; j <= n; j++)
if (!vis[j] && (u==-1 || cost[u] > cost[j]))
u = j;
vis[u] = true;
ans += cost[u];
// printf("find u = %d , cost[u] = %lld, pre[u] = %d\n", u, cost[u], pre[u]);
for (int j = 1; j <= n; j++)
if (!vis[j] && g[u][j] < cost[j]) {
cost[j] = g[u][j];
pre[j] = u;
}
}
for (int i = 1; i <= n; i++) {
if (!pre[i]) v1.push_back(i);
else v2.push_back({pre[i], i});
}
cout << ans << endl;
int sz = v1.size();
cout << sz << endl;
for (int i = 0; i < sz; i++) {
if (i) cout << " ";
cout << v1[i];
}
cout << endl;
sz = v2.size();
cout << sz << endl;
for (int i = 0; i < sz; i++)
cout << v2[i].first << " " << v2[i].second << endl;
return 0;
}