2024杭电多校第8场
8
1005 cats 的二分答案 (hdu7521)
又是来自队友的思路,orz
设 \(x = r - l + 1\),由于二分操作最多进行 \(\log x\) 次,\(k\geq \log x\) 时不可能出现程序崩溃情况,由此可将需要讨论的 \(k\) 范围缩减至 \(60\) 以下。每次二分所产生新的子区间最多有两种不同情况,则总共存在不超过 \(2\log x\) 种区间,因此可将区间长度当作状态处理。设 \(f[i][j]\) 表示长度为 \(i\) 的区间、当前已有 \(j\) 次下标越界的情况总数,记忆化搜索求解。复杂度 \(\log^2 x\),可能还带一点unordered_map的常数,题解的dp常数小些,但写着不太顺手
记忆化搜索代码:
unordered_map <ll, ll> mp[61];
void dfs(ll x) {
if(x <= 0) return;
mp[0][x] = 1; // 二分恰好找到答案,下标不越界,也不需要继续dfs
ll mid = (x + 1) / 2;
if(!mp[0][mid - 1]) dfs(mid - 1);
for(int i = 1; i <= k; i++) {
mp[i][x] += mp[i - 1][mid - 1]; // 向前半段区间寻找,说明下标已越界
}
if(!mp[0][x - mid]) dfs(x - mid);
for(int i = 0; i <= k; i++) {
mp[i][x] += mp[i][x - mid]; // 下标未越界
}
}
1006 cats的最小生成树 (hdu7522)
对于总共 \(m\) 条边而言,有效操作次数不会超过 \(k = \lfloor m/(n - 1)\rfloor\) 次,每次对 \(n\) 个点做最小生成树,考虑用 \(k\) 个并查集维护每次操作过程中图的连通性,整体空间复杂度 \(O(m)\). 连边操作时,二分查找左右端点不连通的最早时刻,极端情况下时间复杂度 \(m\log m\). 最后对每个并查集检查连通性,若第 \(i\) 次操作时图已经无法连通,则大于该操作次数的边都不会被加入生成树,输出-1.
int lev = m / (n - 1); // 即题解中的k
if(lev == 0) {
for(int i = 1; i <= m; i++) {
int x, y;
scanf("%d%d", &x, &y);
printf("-1 ");
}
printf("\n");
return; // 按我的代码不特判就会re()
}
for(int i = 1; i <= lev; i++) {
for(int j = 0; j <= n + 1; j++) {
f[i].push_back(j);
}
}
for(int i = 1; i <= m; i++) {
int x, y, l = 1, r = lev;
scanf("%d%d", &x, &y);
ans[i] = lev + 1;
if(find(lev, x) == find(lev, y)) continue;
while(l <= r) {
int mid = (l + r) / 2;
if(find(mid, x) != find(mid, y)) {
ans[i] = mid;
r = mid - 1;
} else l = mid + 1;
}
f[ans[i]][find(ans[i], x)] = find(ans[i], y);
}
int flag = lev + 1;
for(int i = 1; i <= lev; i++) {
int cnt = 0;
for(int j = 1; j <= n; j++) {
if(f[i][j] == j) cnt++;
}
if(cnt > 1) {
flag = i;
break;
}
}
for(int i = 1; i <= m; i++) {
if(ans[i] >= flag) printf("-1 ");
else printf("%d ", ans[i]);
}
1012 cats 的电脑中毒 (hdu7528)
非常好题目,正解就是贪心的题还能想假也是离谱()将两个字符串不同字符的位置数量看作它们的“距离”,题意即转化为:求一个字符串 \(x\),其与三个给定字符串距离的最小值最大。嗯,看上去有点像二分或者dp,但经过我和wyq的尝逝,这两种思路都不对。
对于给定字符串 \(a,b,c\) 的第 \(i\) 位,若 \(a[i] = b[i] = c[i]\),\(x[i] \neq a[i]\) 显然是最优的,统计三个字符串相等的情况次数 \(s\);若 \(a[i] = b[i] \neq c[i]\),可暂时令 \(x[i] = c[i]\). 统计每个字符串与另外两者不等的次数,记作 \(cnt_a,cnt_b,cnt_c\). 此时 \(d_{ax} = s + cnt_b + cnt_c,\space d_{bx} = s + cnt_a + cnt_c, \space d_{cx} = s + cnt_a + cnt_b\),假设 \(cnt_a \leq cnt_b\leq cnt_c\),对于当前最小距离 \(d_{cx}\) 而言,适当调整 \(a[i] = b[i] \neq c[i]\) 情况下的取值、即令部分 \(x[i] = a[i],\space min(d_{ax} - k, d_{bx} - k, d_{cx} + k) = d_{cx} + k\) 显然更佳;该调整操作最多对一个字符串进行,若调整两个字符串的取值,使这两个字符串距离不变、另一字符串距离减小,答案不会更优。调整应当使 \(d_{cx}'\) 与较小的 \(d_{bx}'\) 尽可能接近,即有最终答案 \(d = s + cnt_a + (cnt_b + cnt_c) / 2\).