ABC364题解(D-G)
D
先对 \(a\) 从小到大排序。
将题目转化成找到最小的 \(d\),使得恰好有 \(k\) 个 \(a_i\in [b-d,b+d]\)。
对于每个询问 \(b,k\),考虑二分答案。
设待检查的答案为 \(d\),二分找到最小的 \(p1\) 使得 \(a_{p1}\geq b-d\) 和最小的 \(p2\) 使得 \(a_{p2}> b+d\),包含的数的个数即为 \(p2-p1\)。
- 如果 \(p2-p1\ge k\),\(r\gets mid\)。
- 否则,\(l\gets mid+1\)。
答案即为 \(r\)。
时间复杂度 \(O(n\log^2n)\)。
E
考虑 dp 求解。
设 \(f(i,j,k)\) 表示 dp 到第 \(i\) 道菜,吃了 \(j\) 盘,总甜度为 \(k\) 时总咸度的最小值。
于是有转移:
\(f(i,j,k)=\min\left(f(i-1,j,k),f(i-1,j-1,k-a_i)+b_i\right)\)。
答案是多少?
注意到最后一道菜随便吃,所以找到最大的 \(j\),使得存在 \(k\in[0,x]\) 满足 \(f(n,j,k)\leq y\)(先满足要求),答案即为 \(\min(j+1,n)\)(最后随便吃)。
如果找不到,答案就是 \(0\)。
复杂度 \(O(n^2V)\)。
F
考虑 kruskal 算法求最小生成树的思想:贪心从小到大选边,如果一条边两端在同一连通块内就不加入图中,否则加入。
注意到 \(n+i\) 号点相当于联通了 \([l_i,r_i]\) 中的所有点,但是暴力加边不可取,可以考虑并查集维护连通块。
具体的,\(n\) 个点所属并查集的根节点代表连通块右端点,合并两个连通块即为把 左侧连通块根节点的父亲 变为 右侧连通块的根节点。
这样我们就可以快速跳过连通块中间部分,快速找到两个连通块的连接处,然后加边。
所以把 \(>n\) 的点按照 \(c_i\) 排序,连接时从 \(l_i\) 所属连通块开始连接,直到 \(r_i\) 和所属连通块联通即可。答案即为连接的连通块数量。
复杂度线性。
厉害做法:
注意到上面并查集的作用实际上是快速找到连通块右端点并删除。有没有一种做法,也能快速找到右端点?
注意到要维护的内容很简单,如果用线段树,1 个 bool 就能维护子树里是否有值(也就是“1”)。
如果要维护的这么简单,不如直接在父节点维护底下每一个儿子是否有值。
bool 太浪费了,用一个 bit 维护就行了。
都用 bit 维护了,于是直接维护一个 ull
,这样就能一次性维护高达 64 个儿子的状态了!
因为可以 \(O(1)\) 定位叶子的位置,所以可以从叶子开始向上找,如果同一块内有,再向下找,一次查找只要 \(O(\log_{64}n)\)!
复杂度变成了 \(O(n\log_{64} n)\),和并查集跑得一样快!
单点修改类似不用 pushup 的线段树。
G
\(k\) 这么小,直接考虑状压 dp。
设 \(f(i,s)\) 表示考虑到点 \(i\),\(i\) 和集合 \(s\) 中的点通过修过的路联通的最小代价。
于是有转移:
\(f(i,s)=\min_{(i,j)\in edge}f(j,u)+w(i,j)\)
\(f(i,s)=\min_{u\subseteq s}\left(f(i,u)+f(i,s-u)\right)\)
注意到 \(f(i,s)\) 依赖于 \(s\) 的子集,所以先从小到大枚举 \(s\),再枚举 \(i\)。
但是转移方成立有同层(同样的\(s\))之间的转移?
注意到第一个式子的转移像是最短路,可以用最短路进行同层的转移。
复杂度 \(O(n3^n+m2^n\log m)\)。
D
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int a[N], n, q;
int chk(int b, int k, int d)
{
int p1 = lower_bound(a + 1, a + n + 1, b - d) - a;
int p2 = upper_bound(a + 1, a + n + 1, b + d) - a - 1;
return p2 - p1 + 1;
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);
cin >> n >> q;
for(int i = 1; i <= n; i ++) cin >> a[i];
sort(a + 1, a + n + 1);
while(q --)
{
int b, k; cin >> b >> k;
int l = 0, r = 2e8;
while(l < r)
{
int mid = l + r >> 1;
if(chk(b, k, mid) >= k) r = mid;
else l = mid + 1;
}
cout << r << "\n";
}
return 0;
}
E
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 85, M = 1e4 + 5;
ll f[N][N][M], n, a[N], b[N], x, y;
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);
cin >> n >> x >> y;
for(int i = 1; i <= n; i ++) cin >> a[i] >> b[i];
memset(f, 0x3f, sizeof f);
f[0][0][0] = 0;
for(int i = 1; i <= n; i ++)
{
for(int j = 0; j <= i; j ++)
{
for(int k = 0; k <= x; k ++)
{
f[i][j][k] = min(f[i][j][k], f[i - 1][j][k]);
if(k - a[i] >= 0 && j && f[i - 1][j - 1][k - a[i]] + b[i] <= y) f[i][j][k] = min(f[i][j][k], f[i - 1][j - 1][k - a[i]] + b[i]);
}
}
}
for(int i = n; i >= 0; i --)
{
for(int j = 0; j <= x; j ++)
{
if(f[n][i][j] <= y)
return cout << min(n, (ll)i + 1) << "\n", 0;
}
}
cout << 0;
return 0;
}
F(并查集)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
int n, q, fa[N];
struct node {int l, r, v;} a[N];
int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);
cin >> n >> q;
for(int i = 1; i <= n; i ++) fa[i] = i;
for(int i = 1; i <= q; i ++) cin >> a[i].l >> a[i].r >> a[i].v;
sort(a + 1, a + q + 1, [](node &x, node &y) {return x.v < y.v;});
ll ans = 0;
for(int i = 1; i <= q; i ++)
{
int u = find(a[i].l), ed = find(a[i].r);
ans += a[i].v;
while(u != ed) fa[u] = find(u + 1), u = find(u), ans += a[i].v;
}
if(find(1) != n) cout << -1, 0;
else cout << ans;
return 0;
}
F 厉害做法:\(O(n\log_{64}n)\)
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 5;
int n, q;
struct node {int l, r, v;} a[N];
using ull = unsigned long long;
struct FastSet
{
static const int B = 64;
vector<vector<ull>> a;
int n, h;
FastSet(int __n)
{
n = __n;
while(__n > 1)
{
__n = (__n + B - 1) / B, h ++;
a.emplace_back(__n);
}
}
inline void set(int pos)
{
for(int i = 0; i < h; i ++)
{
a[i][pos / B] |= (1ull << pos % B);
pos /= B;
}
}
inline void reset(int pos)
{
for(int i = 0; i < h; i ++)
{
a[i][pos / B] &= ~(1ull << pos % B);
if(a[i][pos / B]) return;
pos /= B;
}
}
int find_next(int pos)
{
for(int i = 0; i < h; i++)
{
ull d = (a[i][pos / B] >> (pos % B) + 1);
if(pos % B != 63 && d)
{
pos += __builtin_ctzll(d) + 1;
for(int j = i - 1; j >= 0; j--)
{
pos *= B;
pos += __builtin_ctzll(a[j][pos / B]);
}
return pos;
}
pos /= B;
}
return n;
}
};
int main()
{
ios_base::sync_with_stdio(false);cin.tie(0);
cin >> n >> q;
for(int i = 1; i <= q; i ++) cin >> a[i].l >> a[i].r >> a[i].v;
sort(a + 1, a + q + 1, [](node &x, node &y) {return x.v < y.v;});
FastSet st(n + 1);
for(int i = 1; i <= n; i ++) st.set(i);
ll re = 0;
for(int i = 1; i <= q; i ++)
{
int l = a[i].l, r = a[i].r, c = a[i].v;
l --;
int cnt = 0;
while(1)
{
int v = st.find_next(l);
if(v >= r) break;
st.reset(v);
++cnt;
}
re += 1ll * c * (1 + cnt);
}
cout << (st.find_next(0) == n ? re : -1);
return 0;
}
G
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 4e3 + 5, M = 1.6e4 + 5, K = 9;
ll f[N][(1 << K) + 5];
int n, m, k;
int fst[N], nxt[M], to[M], w[M], h = 2;
void add(int x, int y, int z)
{
nxt[h] = fst[x], fst[x] = h, to[h] = y, w[h] = z, h ++;
}
void spread(int j)
{
static bool inq[N];
queue<int> q;
for(int i = 1; i <= n; i ++) q.push(i), inq[i] = 1;
while(q.size())
{
auto t = q.front(); q.pop();
inq[t] = 0;
for(int o = fst[t]; o; o = nxt[o])
{
int i = to[o], w = ::w[o];
if(f[i][j] > f[t][j] + w)
{
f[i][j] = f[t][j] + w;
if(!inq[i]) q.push(i), inq[i] = 1;
}
}
}
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);
cin >> n >> m >> k; k --;
for(int i = 1; i <= m; i ++)
{
int x, y, z; cin >> x >> y >> z;
add(x, y, z);
add(y, x, z);
}
memset(f, 0x3e, sizeof f);
for(int i = 0; i < k; i ++)
f[i + 1][1 << i] = 0;
for(int j = 0; j < (1 << k); j ++)
{
for(int i = 1; i <= n; i ++)
for(int s = j; s > (j ^ s); s = (s - 1) & j)
f[i][j] = min(f[i][j], f[i][s] + f[i][j ^ s]);
spread(j);
}
for(int i = k + 1; i <= n; i ++) cout << f[i][(1 << k) - 1] << "\n";
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话