AtCoder Grand Contest 032 题解
本文目录(18 节)
Limited Insertion
倒着考虑,每次找到最大的 满足 然后删掉,如果不存在则无解。
const int N = 107;
int n, a[N], ans[N];
int main() {
rd(n), rda(a, n);
for (int i = n; i; i--) {
int p = 0;
for (int j = i; j && !p; j--)
if (a[j] == j) p = j;
if (!p) return prints("-1"), 0;
ans[i] = p;
for (int j = p; j < i; j++) a[j] = a[j+1];
}
for (int i = 1; i <= n; i++) print(ans[i]);
return 0;
}
Balanced Neighbors
构造方式见代码。
int main() {
int n;
rd(n);
if (n == 3) {
print(2);
print(1, 3);
print(2, 3);
return 0;
}
if (n == 4) {
print(4);
print(1, 2);
print(1, 3);
print(4, 2);
print(4, 3);
return 0;
}
vector<pi> e;
vi a, b;
int m = n & 1;
n -= m;
for (int i = 1; i <= n >> 1; i++) a.pb(i);
for (int i = n; i > n >> 1; i--) b.pb(i);
for (int i = 1; i < n >> 1; i++)
e.pb(mp(a[i-1], a[i])),
e.pb(mp(b[i-1], b[i])),
e.pb(mp(a[i-1], b[i])),
e.pb(mp(b[i-1], a[i]));
if (m) {
e.pb(mp(n + 1, a[0])),
e.pb(mp(n + 1, b[0])),
e.pb(mp(n + 1, a.back())),
e.pb(mp(n + 1, b.back()));
} else {
e.pb(mp(a.back(), a[0])),
e.pb(mp(b.back(), b[0])),
e.pb(mp(a.back(), b[0])),
e.pb(mp(b.back(), a[0]));
}
print(e.size());
for (pi o : e) print(o.fi, o.se);
return 0;
}
Three Circuits
题意
- 给定一张 个点 条边的无向图,问能否将无向图拆成三个环,使得每条边恰好在一个环中。
- 。
题解
首先要是欧拉回路。
若度数最大值 则有解, 则无解,接下来考虑 的情况。
若度数为 的点超过 个则有解, 个则无解,接下来考虑 个的情况。
只有两种形态,一种有解一种无解,讨论一下即可。
代码
const int N = 1e5 + 7;
int n, m, d[N], X, Y;
vi e[N];
void dfs(int x, int f) {
if (x == Y) return;
if (x == X) prints("Yes"), exit(0);
for (int y : e[x])
if (y != f) dfs(y, x);
}
int main() {
rd(n, m);
for (int i = 1, x, y; i <= m; i++)
rd(x, y), ++d[x], ++d[y], e[x].pb(y), e[y].pb(x);
for (int i = 1; i <= n; i++) if (d[i] & 1) return prints("No"), 0;
int mx = *max_element(d + 1, d + n + 1);
if (mx == 2) return prints("No"), 0;
if (mx >= 6) return prints("Yes"), 0;
int cnt = 0;
for (int i = 1; i <= n; i++) cnt += d[i] == 4;
if (cnt == 1) return prints("No"), 0;
if (cnt >= 3) return prints("Yes"), 0;
for (int i = 1; i <= n; i++)
if (d[i] == 4) {
if (X) Y = i;
else X = i;
}
for (int z : e[X]) dfs(z, X);
prints("No");
return 0;
}
Rotation Sort
题意
- 给定一个 的排列 ,你要将其变成升序。
- 有两种操作:
- 选择一个 满足 ,将 替换为 ,代价为 。
- 选择一个 满足 ,将 替换为 ,代价为 。
- 求最小代价。
- 。
题解
显然操作等价于将某个数左移或者右移。
考虑 DP,设 表示考虑前 个数,其中最后一个没有被移动的数为 的最小代价,分 和 转移即可,时间复杂度 。
代码
const int N = 5e3 + 7;
const ll inf = 1e18;
int n, a, b, p[N];
ll f[N][N], ans = inf;
int main() {
rd(n, a, b), rda(p, n);
for (int i = 0; i <= n; i++)
for (int j = 0; j <= n; j++)
f[i][j] = inf;
f[0][0] = 0;
for (int i = 1; i <= n; i++)
for (int j = 0; j <= n; j++)
if (p[i] > j)
f[i][j] = min(f[i][j], f[i-1][j] + a),
f[i][p[i]] = min(f[i][p[i]], f[i-1][j]);
else f[i][j] = min(f[i][j], f[i-1][j] + b);
for (int i = 0; i <= n; i++) ans = min(ans, f[n][i]);
print(ans);
return 0;
}
Modulo Pairing
题意
- 给定模数 和 个整数,你要将这些整数分成 对。
- 对于每一对 ,其权值为 。
- 你要最小化这 对权值的最大值。
- ,。
题解
有结论:按从小到大排序后,一定存在一个最优解,是以某个位置为界,两边分别首位匹配,满足左边每一对的和都 ,右边每一对的和都 。
二分这个位置,时间复杂度 。
代码
const int N = 2e5 + 7;
int n, m, a[N], ans;
inline bool pd(int o) {
for (int i = o << 1 | 1; i <= n << 1; i++)
if (a[i] + a[((n+o)<<1|1)-i] < m) return 0;
return 1;
}
int main() {
rd(n, m), rda(a, n << 1);
sort(a + 1, a + (n << 1 | 1));
int l = 0, r = n;
while (l < r) {
int d = (l + r) >> 1;
if (pd(d)) r = d;
else l = d + 1;
}
int p = l << 1;
for (int i = 1; i <= p; i++)
ans = max(ans, a[i] + a[p+1-i]);
for (int i = p + 1; i <= n << 1; i++)
ans = max(ans, a[i] + a[(n<<1|1)+p-i] - m);
print(ans);
return 0;
}
One Third
题意
- 有一个披萨,将它在 条随机的半径切一刀。
- 你会选择若干块相邻的披萨饼,使其总和最接近 。
- 求选择的披萨饼大小与 之差的绝对值的期望值。
- ,答案对 取模。
题解
先转化,对于每一刀,先将其染成红色,再在 和 各切一刀,分别染蓝色和绿色。
将每一刀 ,于是问题等价于有一条长 的线段, 处为红, 处为蓝,中间还有 个位置和颜色随机的点,将整个线段分成了 段,求最短的两端颜色不同的线段长度的期望。
把所有线段拿出来排序,考虑答案为第 短的线段,经过积分可以得到为 。
考虑最短的,答案为 ,如果同色考虑次短的,要加上 乘上同色的概率 ,以此类推,答案为 。
时间复杂度 。
代码
int n;
modint ans, a = 1;
int main() {
rd(n), init(max(n, 3));
for (int k = 1; k <= n; k++) ans += (a *= v[3]) * v[n+1-k];
print(ans * v[n]);
return 0;
}
评论
暂无已公开评论。