2022“杭电杯”中国大学生算法设计超级联赛(5)
Slipper
给一颗以1为根有边权的数,且当\(|dep_u-dep_v|==k\)时\(u\)可以花费\(p\)走到\(v\),求s到t的最短路。
每一个dep建两个点一个从树上的点连入,一个连向树上的点,中间连花费p的边
前向星比vector快了不止一倍
using IO::gi;
using IO::pi;
using IO::pc;
const int N = 1000000 + 5;
priority_queue<pair<ll, int>, vector<pair<ll, int> >, greater<pair<ll, int> > > q;
bool vis[N + N + N];
ll dis[N + N + N];
int n, fir1[N], ecnt1, fir[N + N + N], ecnt;
struct Edge {
int to, nxt, w;
} edge1[N << 1], edge[N * 6];
void addedge(int u, int v, int w) {
edge[++ecnt] = (Edge){v, fir[u], w}; fir[u] = ecnt;
}
void dfs(int u, int fa, int dep) {
addedge(u, dep + n, 0);
addedge(dep + n + n, u, 0);
for (int e = fir1[u]; e; e = edge1[e].nxt) {
int v = edge1[e].to;
if (v == fa) continue;
dfs(v, u, dep + 1);
}
}
void Add(int u, int v) {
edge1[++ecnt1] = (Edge){v, fir1[u], 0}; fir1[u] = ecnt1;
edge1[++ecnt1] = (Edge){u, fir1[v], 0}; fir1[v] = ecnt1;
}
int main() {
// freopen("a.in", "r", stdin);
int T = gi();
while (T--) {
n = gi();
for (int i = 1; i <= n; ++i) fir1[i] = 0;
for (int i = 1; i <= n + n + n; ++i) fir[i] = 0;
ecnt1 = 0, ecnt = 0;
for (int i = 1; i < n; ++i) {
int u = gi(), v = gi(), w = gi();
Add(u, v);
addedge(u, v, w);
addedge(v, u, w);
}
dfs(1, 0, 1);
int k = gi(), p = gi();
for (int i = 1; i <= n - k; ++i) {
addedge(n + i, n + n + i + k, p);
addedge(n + n + i + k, n + i, p);
}
int s = gi(), t = gi();
for (int i = 1; i <= n + n + n; ++i) {
dis[i] = 1e18;
vis[i] = 0;
}
q.emplace(dis[s] = 0, s);
while (q.size()) {
int u = q.top().second; q.pop();
if (vis[u]) continue;
vis[u] = 1;
for (int e = fir[u]; e; e = edge[e].nxt) {
int v = edge[e].to;
if (dis[v] > dis[u] + edge[e].w) q.emplace(dis[v] = dis[u] + edge[e].w, v);
}
}
printf("%lld\n", dis[t]);
}
return 0;
}
Bragging Dice
题目读错,自闭2个h
#include <bits/stdc++.h>
using namespace std;
int n, x, A[10], B[10];
int main() {
int T; scanf("%d", &T);
while (T--) {
scanf("%d", &n);
for (int i = 1; i <= 6; ++i) A[i] = B[i] = 0;
bool uniA = 1, uniB = 1;
for (int i = 1; i <= n; ++i) {
int x; scanf("%d", &x);
if (A[x]) uniA = 0;
A[x] = 1;
}
for (int i = 1; i <= n; ++i) {
int x; scanf("%d", &x);
if (B[x]) uniB = 0;
B[x] = 1;
}
bool flag = 0;
for (int i = 2; i <= 6; ++i) flag |= A[i] && B[i];
if (uniA && uniB) puts("Just a game of chance.");
else puts("Win!");
}
return 0;
}
Buy Figurines
n个人去m个窗口购物,每个人有到达时间\(a_i\),花费时间\(s_i\),当有一人到达时,他会去等待人数最少的窗口(人数一样去编号小的)等待。问最后一人离开的时间。
用STL模拟,一个堆存每个人的结束时间和窗口,一个set存人数和窗口。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct A {
int a, s;
} p[200005];
priority_queue<pair<ll, int>, vector<pair<ll, int> >, greater<pair<ll, int> > > hp; // edtime windows
set<pair<int, int> > win; // num_p windows
ll ed[200005];
int n, m, cnt[200005];
int main() {
int T; scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) scanf("%d%d", &p[i].a, &p[i].s);
sort(p + 1, p + n + 1, [](const A &l, const A &r) { return l.a < r.a; });
while (hp.size()) hp.pop();
win.clear();
for (int i = 1; i <= m; ++i) {
ed[i] = 1;
win.emplace(cnt[i] = 0, i);
}
for (int i = 1; i <= n; ++i) {
while (hp.size() && hp.top().first <= p[i].a) {
int tmp = hp.top().second;
win.erase(make_pair(cnt[tmp]--, tmp));
win.emplace(cnt[tmp], tmp);
hp.pop();
}
int tmp = win.begin()->second;
win.erase(win.begin());
win.emplace(++cnt[tmp], tmp);
hp.emplace(ed[tmp] = max(ed[tmp], (ll)p[i].a) + p[i].s, tmp);
}
ll ans = 0;
for (int i = 1; i <= m; ++i) ans = max(ans, ed[i]);
printf("%lld\n", ans);
}
return 0;
}