2018 Benelux Algorithm Programming Contest (BAPC 18)
A - A Prize No One Can Win
int main() {
IOS; cin >> n >> m; VI a(n); k = 1;
for (auto &i : a) cin >> i; sort(all(a));
rep (i, 1, n - 1) if (a[i] + a[i - 1] <= m) ++k;
cout << k;
return 0;
}
B - Birthday Boy
int c[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
char s[25];
int calc(PII a, PII b) {
int ans = b.se - 1 - a.se + (a.fi == b.fi ? 0 : c[a.fi]);
rep(i, a.fi + 1, b.fi - 1) ans += c[i];
return ans;
}
int main() {
scanf("%d", &n); vector<PII> a(n);
for (auto& i : a) scanf("%s %d-%d", s, &i.fi, &i.se); sort(all(a));
int x = a[0].fi, y = a[0].se - 1, k = calc(a.back(), { 12, 31 }) + calc({ 1, 1 }, a[0]) + 2;
if (!y) x = x == 1 ? 12 : x - 1, y = c[x];
rep(i, 1, n - 1) {
int cur = calc(a[i - 1], a[i]), cx = a[i].fi, cy = a[i].se - 1;
if (!cy) cx = cx == 1 ? 12 : cx - 1, cy = c[cx];
if (cur > k || (cur == k && PII{ x, y } <= PII{ 10, 27 } && PII{ cx, cy } > PII{10, 27}))
k = cur, x = a[i].fi, y = a[i].se - 1;
}
if (x < 10) cout << 0; cout << x << '-';
if (y < 10) cout << 0; cout << y;
return 0;
}
C - Cardboard Container
int main() {
IOS; cin >> n; ans = 2 + n * 4;
rep (c, 1, n) {
rep (h, 1, c) {
if (c * h > n) break;
if (n % (c * h) == 0) umin(ans, c * h + n / h + n / c << 1);
}
}
cout << ans;
return 0;
}
F - Financial Planning
二分, 注意再循环的时候一旦成功就跳出, 否则会爆ll
int main() {
IOS; cin >> n >> m; vector<PLL> a(n);
for (auto &i : a) cin >> i.fi >> i.se;
ll l = 1, r = 2e9;
while (l < r) {
ll mid = l + r >> 1;
ll ans = 0;
for (auto &p : a) {
ans += max(0ll, p.fi * mid - p.se);
if (ans >= m) break;
}
if (ans >= m) r = mid;
else l = mid + 1;
}
cout << l;
return 0;
}
G - Game Night
最终序列是ABC的全排列, 起点任意, 干脆最终状态为 ABC 或者 ACB
然后通过滑动窗匹配就行了
int c[3];
string s, t[3], a, b;
int work(string& s, string& t, string a) {
int ans = 0, cnt = 0;
rep (i, 0, n - 1) cnt += s[i] != t[i]; ans = cnt;
rep (i, 0, n - 2) {
if (s[i] == a[0]) ++cnt;
if (s[i + c[a[0] - 'A']] == a[0]) --cnt;
if (s[i + c[a[0] - 'A']] == a[1]) ++cnt;
if (s[i + c[a[0] - 'A'] + c[a[1] - 'A']] == a[1]) --cnt;
if (s[i + c[a[0] - 'A'] + c[a[1] - 'A']] == a[2]) ++cnt;
if (s[i + c[a[0] - 'A'] + c[a[1] - 'A'] + c[a[2] - 'A']] == a[2]) --cnt;
umin(ans, cnt);
}
return ans;
}
int main(){
IOS; cin >> n >> s;
for (auto i : s) ++c[i - 'A']; s += s;
rep (i, 0, 2) string(c[i], 'A' + i).swap(t[i]);
a = t[0] + t[1] + t[2], b = t[0] + t[2] + t[1];
cout << min(work(s, a, "ABC"), work(s, b, "ACB"));
return 0;
}
I - In Case of an Invasion, Please...
最小化值, 想二分, 找到可用边, 然后网络流
但复杂度必炸, 注意到最多10个避难点
最多有 1 << 10 种状态, 复杂度就够了
把能到达完全相同数量和编号的点合并, 最多有1024种,
s 向 这1024状态连边, 1024在向 避难点 连边, 避难点在向 t 连边
相当与我们实在二分这1024种状态到避难点的最小最大长度, 那最多有 1024 * 10条边
排序二分边的序号即可
const int N = 1e5 + 15, M = 2e4 + 5;
const ll inf = 1ll << 60;
int n, m, _, k;
int a[N];
ll dis[11][N], sum;
bool v[N];
PII sh[11];
vector<PII> e[N];
void dij(int s, ll* d) {
memset(v, 0, sizeof v);
priority_queue<pair<ll, int>> q; q.push({d[s] = 0, s});
while (!q.empty()) {
int x = q.top().se; q.pop();
if (v[x]) continue; v[x] = 1;
for (auto &y : e[x]) if (d[y.fi] > d[x] + y.se)
q.push({-(d[y.fi] = d[x] + y.se), y.fi});
}
}
int h[1050], ne[M], to[M], tot, now[1050];
int d[1050], s = 1025, t = 1026;
ll co[M], st[1050];
void add(int u, int v, ll c) {
ne[++tot] = h[u]; to[h[u] = tot] = v; co[tot] = c;
ne[++tot] = h[v]; to[h[v] = tot] = u; co[tot] = 0;
}
bool bfs() {
memset(d, 0, sizeof d); memcpy(now, h, sizeof h);
queue<int> q; q.push(s); d[s] = 1;
while (!q.empty()) {
int x = q.front(); q.pop();
for (int i = h[x]; i; i = ne[i]) if (co[i]) {
int y = to[i];
if (d[y]) continue;
d[y] = d[x] + 1; q.push(y);
if (y == t) return 1;
}
}
return 0;
}
ll dinic(int x, ll flow) {
if (x == t) return flow;
ll rest = flow, k;
for (int& i = now[x]; i && rest; i = ne[i]) if (co[i]) {
int y = to[i];
if (d[y] != d[x] + 1) continue;
k = dinic(y, min(rest, co[i]));
if (!k) { d[y] = 0; continue; }
co[i] -= k, co[i ^ 1] += k; rest -= k;
}
return flow - rest;
}
bool check(ll mid) {
memset(h, 0, sizeof h); memset(st, 0, sizeof st); tot = 1;
rep (i, 1, n) {
int cur = 0;
rep (j, 1, k) if (dis[j][i] <= mid) cur ^= 1 << j - 1;
st[cur] += a[i];
}
rep (i, 0, (1 << k) - 1) if (st[i]) {
rep (j, 1, k) if (i >> j - 1 & 1) add(i, j + t, inf);
add(s, i, st[i]);
}
rep (i, 1, k) add(i + t, t, sh[i].se);
ll flow = 0, mx = 0;
while (bfs()) while(flow = dinic(s, inf)) mx += flow;
return mx == sum;
}
int main() {
read(n, m, k); vector<ll> c;
memset(dis, 0x3f, sizeof dis);
rep (i, 1, n) read(a[i]), sum += a[i];
rep (i, 1, m) {
int u, v, c; read(u, v, c);
e[u].pb({v, c}); e[v].pb({u, c});
}
rep (i, 1, k) {
read(sh[i].fi, sh[i].se); dij(sh[i].fi, dis[i]);
rep (j, 1, n) c.emplace_back(dis[i][j]);
}
sort(all(c));
int l = 1, r = unique(all(c)) - c.begin(), ans;
while (l <= r) {
ll mid = l + r >> 1;
if (check(c[mid - 1])) r = mid - 1, ans = mid;
else l = mid + 1;
}
write(c[ans - 1]);
return 0;
}
J - Janitor Troubles
多边形面积公式
int main() {
IOS; double a, b, c, d; cin >> a >> b >> c >> d;
double p = (a + b + c + d) / 2;
cout << setprecision(7) << sqrt((p - a) * (p - b) * (p - c) * (p - d));
return 0;
}
K - Kingpin Escape
不存在割边加点
int deg[N];
VI h[N], a;
void dfs(int x, int f) {
if (deg[x] == 1) a.pb(x);
for (auto y : h[x]) if (y != f) dfs(y, x);
}
int main(){
IOS; cin >> n >> m; ++m;
rep (i, 2, n) {
int u, v; cin >> u >> v; ++v, ++u;
h[u].pb(v); h[v].pb(u); ++deg[v]; ++deg[u];
}
dfs(m, 0);
cout << (a.size() + 1 >> 1) << '
';
rep (i, 1, a.size() >> 1) cout << a[i - 1] - 1 << ' ' << a[i + a.size() / 2 - 1] - 1 << '
';
if (a.size() & 1) cout << a[a.size() >> 1] - 1 << ' ' << a.back() - 1;
return 0;
}