The 3rd Universal Cup. Stage 14: Harbin
C. Giving Directions in Harbin
一个简单的模拟题,主要是处理好转向。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
vector<string> dir = {"N", "E", "S", "W"};
void solve(){
int n;
cin >> n;
vector<pair<string,int>> op(n);
for(auto &[d, x] : op)
cin >> d >> x;
vector<string> res;
string staD = op[0].first;
int t = 0;
if(staD == "E") t = 1;
else if(staD == "S") t = 2;
else if(staD == "W") t = 3;
for(auto [d, x] : op) {
if(dir[t] != d) {
int t1 = (t + 1) % 4;
int t2 = (t + 3) % 4;
if(dir[t1] == d) res.push_back("R"), t = t1;
else if(dir[t2] == d) res.push_back("L"), t = t2;
}
res.push_back("Z " + to_string(x));
}
cout << res.size() << " " << staD << "\n";
for(auto i : res)
cout << i << "\n";
return;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while(T --)
solve();
return 0;
}
G. Welcome to Join the Online Meeting!
我们称不能拉人的为特殊点。
我们记无向图的的时候本质是对每一条边记两条有向边。我们把图中所有以特殊点为起点的边删掉。
找到任意一个非特殊点的点作为起点,从这个点开始进行 bfs,检查能否遍历完整张图,并记录每个点是被哪个点遍历到的。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
using vi = vector<int>;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m, k;
cin >> n >> m >> k;
vi cannot(n + 1);
for(int i = 0, x; i < k; i ++) {
cin >> x;
cannot[x] = 1;
}
vector<vi> g(n + 1);
for(int u, v; m; m --) {
cin >> u >> v;
if(cannot[u] and cannot[v]) continue;
if(cannot[u]) {
g[v].push_back(u);
} else if(cannot[v]) {
g[u].push_back(v);
} else {
g[u].push_back(v), g[v].push_back(u);
}
}
int root = -1;
for(int i = 1; i <= n; i ++) {
if(cannot[i]) continue;
root = i;
break;
}
if(root == -1) {
cout << "No\n";
return 0;
}
queue<int> que;
vector<pair<int,vi>> res;
vi vis(n + 1);
que.push(root), vis[root] = 1;
while(not que.empty()) {
int x = que.front();
que.pop();
vi nxt;
for(auto y : g[x]) {
if(vis[y]) continue;
que.push(y), vis[y] = 1;
nxt.push_back(y);
}
if(nxt.empty()) continue;
res.emplace_back(x, nxt);
}
for(int i = 1; i <= n; i ++) {
if(vis[i]) continue;
cout << "No\n";
return 0;
}
cout << "Yes\n" << res.size() << "\n";
for(auto [x, nxt] : res) {
cout << x << " " << nxt.size();
for(auto i : nxt) cout << " " << i;
cout << "\n";
}
return 0;
}
J. New Energy Vehicle
一个比较显然的思路是,对于电池的使用,我们优先选择充电站近的电池。因此我们可以用优先队列维护选择电池的策略。
为什么这么做复杂度没有问题?如果每次电池用的很少,则自然是\(O(1)\) 的,如果我某一次电池使用的很多,比如达到了\(O(n)\)的级别,哪么之后的每次至多只能使用一个电池。
因此我认为,复杂度最高的情况是,每次都使用\(O(\sqrt n)\)块电池。因此这样的话,复杂度是\(O(n \sqrt n \log n)\)
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
using pii = pair<int,int>;
const int inf = LLONG_MAX / 2;
void solve() {
int n, m;
cin >> n >> m;
vi a(n + 1);
for(int i = 1; i <= n; i ++) cin >> a[i];
vi b = a;
vector<pii> charge(m);
for(auto &[x, t] : charge) cin >> x >> t;
vi lst(n + 1, inf), suf(m + 1);
for(int i = m - 1; i >= 0; i --) {
auto [pos, ti] = charge[i];
suf[i] = lst[ti], lst[ti] = i;
}
int now = 0;
priority_queue<pii, vector<pii>, greater<pii>> bank;
for(int i = 1; i <= n; i ++)
bank.emplace(lst[i], i);
for(int i = 0; i < m; i ++) {
auto[x, t] = charge[i];
while(now < x and not bank.empty()) {
auto [it, p] = bank.top();
bank.pop();
int y = min(x - now, b[p]);
now += y, b[p] -= y;
if(b[p] > 0 and p != t) bank.emplace(it, p);
}
if(now == x) {
b[t] = a[t];
bank.emplace(suf[i], t);
}else {
break;
}
}
for(auto i : b) {
now += i;
}
cout << now << "\n";
}
i32 main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while(T --)
solve();
return 0;
}
K. Farm Management
如果我们消除了某一种农作物的限制,则我们是不会选择比这种农作物更廉价的农作物。
我们选择农作物的时候肯定是优先选择价值更高的农作物,因此我们按照价值排序。
题目保证了$\sum l \le m $,因此对于每一种农作物,我们可以先操作最低限制,这样剩下的额外农作物我们就可以任意操作。
我们从价值低到高枚举消除哪一种农作物的限制。对于当前农作物,我们首先舍弃掉最低限制,把多余的时间都用来贪心的选择高价价值的农作物,如果所有高价值农作物都选满之后依旧有空余的时间,我们则可以用当前的农作物填满。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
i32 main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<array<int,3>> c(n + 1);
for(int i = 1; i <= n; i ++) {
int w, l, r;
cin >> w >> l >> r;
c[i] = {w, l, r - l};
}
ranges::sort(c);
int sum = 0, used = 0;
for(int i = 1; i <= n; i ++) {
auto [wi, li, ri] = c[i];
sum += li * wi, used += li;
}
vi suf(n + 2), suf_used(n + 2);
for(int i = n; i >= 1; i --) {
suf[i] = suf[i + 1] + c[i][0] * c[i][2];
suf_used[i] = suf_used[i + 1] + c[i][2];
}
int res = 0;
for(int i = 1; i <= n; i ++) {
int now_sum = sum - c[i][1] * c[i][0];
int now_can = m - (used - c[i][1]);
int l = i + 1, r = n + 1, it = -1;
while(l <= r) {
int mid = (l + r) / 2;
if(suf_used[mid] <= now_can) it = mid, r = mid - 1;
else l = mid + 1;
}
now_sum += suf[it];
now_can -= suf_used[it];
it --;
now_sum += now_can * c[it][0];
res = max(res, now_sum);
}
cout << res;
return 0;
}
M. Weird Ceiling
结果一定是因数,我们求出因数后,计算出每个因数的贡献。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
void solve(){
int n;
cin >> n;
vector<ll> div;
for(ll i = 1; i * i <= n; i ++) {
if(n % i == 0) {
div.push_back(i);
div.push_back(n / i);
}
}
sort(div.begin(), div.end());
ll ans = 0;
for(int i = 0; i < div.size() - 1; i ++) {
ans += 1ll * n / div[i] * (div[i + 1] - div[i]);
}
cout << ans + 1 << "\n";
return;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while(T --)
solve();
return 0;
}