7.13 训练日记
题意:
给定
个集合 ,对于每次操作: - 选择两个交集不为空的两个集合
和 ;
- 合并两个集合为。 求可以得到一个同时包含元素 1 和
的集合的最小操作次数,若找不到输出 −1 。
题解:点和集合建边,集合对应的点的权值为1,跑dijkstra,原点为1,求d[m]即可。
int n, m; int d[maxn << 1]; int w[maxn << 1]; vector<int> G[maxn << 1]; void dijkstra() { priority_queue<P, vector<P>, greater<P>> q; // 小根堆 vector<bool> vis(maxn << 1, false); q.push({0, 1}); // 经过的集合个数,起点是1号顶点 d[1] = 0; while (!q.empty()) { auto [x, u] = q.top(); q.pop(); if (vis[u]) continue; vis[u] = true; for (auto i : G[u]) { if (vis[i]) continue; if (x + w[i] < d[i]) { d[i] = x + w[i]; q.push({d[i], i}); } } } } void solve() { cin >> n >> m; for (int i = 1; i <= n + m; i ++) d[i] = inf; for (int i = 1; i <= n; i ++) { int k; cin >> k; w[i + m] = 1; for (int j = 1; j <= k; j ++) { int x; cin >> x; G[x].push_back(m + i); G[m + i].push_back(x); } } dijkstra(); if (d[m] == inf) { cout << -1 << "\n"; } else cout << d[m] - 1 << "\n"; }
题意:
一开始有一些菊花图,然后随便选了两个度数为1的不相连通的点,连一条边。最终得到了一棵树。
现给定这棵树,还原出原来的菊花图,以升序告诉每个菊花图的边数。
题解:
找到一个边缘点,即度数为一的点,它的下一个点一定是菊花图的中心点,再往下搜三个点也是菊花图的中心,以此类推,满足搜索顺序
int n; int in[maxn]; int dis[maxn]; vector<int> G[maxn]; vector<int> vis(maxn, false); vector<int> res; void dfs(int x, int cnt) { vis[x] = 1; if (cnt % 3 == 1) res.push_back(in[x]); for (auto i : G[x]) { if (vis[i]) continue; dfs(i, cnt + 1); } } void solve() { cin >> n; for (int i = 1; i < n; i ++) { int u, v; cin >> u >> v; in[u] ++; in[v] ++; G[u].push_back(v); G[v].push_back(u); } for (int i = 1; i <= n; i++) { if (in[i] == 1) { dfs(i, 0); break; } } sort(res.begin(), res.end()); for (auto i : res) cout << i << " "; cout << '\n'; }
题意:
给定
个商品的价格,以及 个优惠券,每个优惠券只能用于一个商品,且每个商品购买时只能用一个优惠券。 第
个优惠券可以优惠 元,但要求对应商品价格至少 元。 问购买这
个商品需要的最少价格。
题解:
对于不同折扣的优惠券,优先使用大的;
对于一张优惠券,优先给能使用且价格低的商品使用,因为对于价格高的,可能还会有其他选择,就算没有其他选择,也肯定能用低价格剩余的优惠券,可以回退。
int n, m; struct bonus { int l, d; bool operator <(const bonus &a) { return d > a.d; } } b[maxn]; int ans; multiset<int> st; void solve() { cin >> n >> m; for (int i = 1; i <= n; i ++) { int x; cin >> x; ans += x; st.insert(x); } for (int i = 1; i <= m; i ++) { cin >> b[i].l; } for (int i = 1; i <= m; i ++) { cin >> b[i].d; } sort (b + 1, b + m + 1); for (int i = 1; i <= m; i ++) { if (st.lower_bound(b[i].l) != st.end()) { ans -= b[i].d; st.erase(st.lower_bound(b[i].l)); } } cout << ans << endl; }
题意:
题解:
设某数字
int st[maxn]; int a[10010][150]; vector<int> nums; int lowbit(int x) { return x & -x; } void update(int x) { while (x <= nums.size()) { st[x] ++; x += lowbit(x); } } int ask(int x) { int res = 0; while (x) { res += st[x]; x -= lowbit(x); } return res; } void solve() { int n, m; cin >> n >> m; for (int i = 1; i <= n; i ++) { for (int j = 1; j <= m; j ++) { cin >> a[i][j]; nums.push_back(a[i][j]); } } auto get = [&](int x) { return lower_bound(nums.begin(), nums.end(), x) - nums.begin() + 1; }; sort(nums.begin(), nums.end()); nums.erase(unique(nums.begin(), nums.end()), nums.end()); for (int i = 1; i <= n; i ++) { for (int j = 1; j <= m; j ++) { a[i][j] = get(a[i][j]); } } int ans = 0; for (int i = n; i >= 1; i --) { for (int j = 1; j <= m; j ++) { ans += j * (n - i) + ask(a[i][j] - 1); } for (int j = 1; j <= m; j ++) { update(a[i][j]); } } cout << ans << endl; }
题意:
有 N 个房间,每个房间住着一个客人。
条通道连接着这个房间,通道的长度为 。在第 0 天,住在 的这些人感染了病毒。在从此以后的 天里,每天如果一个未感染的客人和已感染的病人间的最短距离小于 ,这个客人就会被感染。 请输出每个客人是在哪天被感染的,如果一直没感染病毒,就输出
。
题解:
开一个小根堆,里面存放当下可能被感染的节点,当前可能被感染的节点一定是被有感染能力的节点传染的,所以更新距离的时候要从算与这一天之前被感染节点的相对距离,即算的其实是这一天中新出队的点的上一个点和它接下里点的距离,更新为
时间复杂度还需要考证
int ans[maxn]; vector<P> G[maxn]; void solve() { int n, m; cin >> n >> m; for (int i = 1; i <= m; i ++) { int u, v, w; cin >> u >> v >> w; G[u].push_back({v, w}); G[v].push_back({u, w}); } priority_queue<P, vector<P>, greater<P>> q; int k; cin >> k; for (int i = 1; i <= k; i ++) { int x; cin >> x; ans[x] = 1; for (auto [u, w] : G[x]) { q.push({w, u}); } } int d; cin >> d; for (int i = 2; i <= d + 1; i ++) { int x; cin >> x; vector<int> tmp; while (!q.empty()) { auto [w, u] = q.top(); if (w > x) break; q.pop(); if (ans[u]) continue; ans[u] = i; tmp.push_back(u); for (auto [v, w1] : G[u]) { if (ans[v]) continue; q.push({w1 + w, v}); } } for (auto v : tmp) for (auto [t, w] : G[v]) q.push({w, t}); } for (int i = 1; i <= n; i ++) cout << ans[i] - 1 << endl; }
题意:构造一个关于
的排序,使得最多有 个位置满足 ,问总共有多少种排序满足.
题解:
错排公式
f[i] = (i - 1) * (f[n - 1] + f[n - 2]);
组合数递推公式
for (int i = 0; i <= n; i ++) { for (int j = 0; j <= i; j ++) { if (!j) f[i][j] = 1; else f[i][j] = f[i - 1][j - 1] + f[i - 1][j]; } }
本题中元素满足
题解 ‘01’串长度等于其对应的十进制数大小,长度最大为
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?