病毒溯源

给定一棵树,树上有\(n\)个节点,编号从\(0\)到\(n-1\),请你输出从根节点开始的最长的一条链,且该链字典序最小

题解:\(dfs\)树的遍历 + 贪心

首先我们先找到入度为\(0\)的点作为根节点,为了保证我们找到第一条最长的链就是字典序最小的链,我们可以贪心的将每个节点的子节点进行排序,这样遍历树的时候优先会遍历节点编号小的点,那么我们得到的第一条最长的链就是字典序最小的点;

那么如何得到一条最长的链:

借助回溯搜索的思想,我们可以在刚进入该节点时,将该节点入队,然后在回溯到该节点时还原现场,将该节点出队,我们维护一条最长的链即可

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 1e4 + 10, M = 4e5 + 10; int n;
vector<int> g[N];
vector<int> ans;
vector<int> v;
int du[N]; void dfs(int u, int par)
{
v.push_back(u);
for (auto v : g[u])
{
if (v == par)
continue;
dfs(v, u);
}
if (v.size() > ans.size())
ans = v;
v.pop_back();
} void solve()
{
cin >> n;
for (int i = 0; i < n; ++i)
{
int k;
cin >> k;
vector<int> v;
for (int j = 1, u; j <= k; ++j)
{
cin >> u;
v.push_back(u);
du[u]++;
}
sort(all(v));
for (auto u : v)
{
g[i].push_back(u);
g[u].push_back(i);
}
}
int rt = 0;
for (int i = 0; i < n; ++i)
{
if (du[i] == 0)
{
rt = i;
break;
}
}
dfs(rt, -1);
cout << ans.size() << endl;
for (int i = 0; i < ans.size(); i++)
cout << ans[i] << "\n "[i < ans.size() - 1];
}
signed main(void)
{
Zeoy;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}

清点代码库

首先假设两个功能模块如果接受同样的输入,总是给出同样的输出,则它们就是功能重复的;其次我们把每个模块的输出都简化为一个整数(在 int 范围内)。于是我们可以设计一系列输入,检查所有功能模块的对应输出,从而查出功能重复的代码。你的任务就是设计并实现这个简化问题的解决方案。

首先在第一行输出不同功能的个数 K。随后 K 行,每行给出具有这个功能的模块的个数,以及这个功能的对应输出。数字间以 1 个空格分隔,行首尾不得有多余空格。输出首先按模块个数非递增顺序,如果有并列,则按输出序列的递增序给出。

题解:\(map\) + 结构体自定义排序

注意:\(map\)能够对\(vector\)自动排序和映射,其他按照题意模拟即可

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 1e5 + 10, M = 4e5 + 10; int n, m;
map<vector<int>, int> mp; struct node
{
int cnt;
vector<int> v;
bool operator<(const node &t) const
{
if (cnt != t.cnt)
return cnt > t.cnt;
else
{
for (int i = 0; i < v.size(); ++i)
{
if (v[i] != t.v[i])
return v[i] < t.v[i];
}
return true;
}
}
}; void solve()
{
cin >> n >> m;
for (int i = 1; i <= n; ++i)
{
vector<int> v;
for (int j = 1; j <= m; ++j)
{
int x;
cin >> x;
v.push_back(x);
}
mp[v]++;
}
vector<node> ans;
for (auto [x, y] : mp)
{
node t;
t.v = x;
t.cnt = y;
ans.push_back(t);
}
sort(all(ans));
cout << ans.size() << endl;
for (int i = 0; i < ans.size(); i++)
{
cout << ans[i].cnt << " ";
for (int j = 0; j < ans[i].v.size(); ++j)
cout << ans[i].v[j] << "\n "[j < ans[i].v.size() - 1];
}
}
signed main(void)
{
Zeoy;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}

还原文件

题解:\(dfs\)回溯搜索

从第一个折线角点开始搜索,设开始匹配的位置为\(p\),如果有一个纸条匹配成功,设匹配成功的纸条长度为\(d\),那么我们就从\(p+d-1\)的位置重新开始匹配,如果匹配失败我们回溯还原现场,注意已经被匹配的纸条不能参与匹配,直到匹配到最后一个折线角点为止

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 1e5 + 10, M = 1e2 + 10; int n, m;
int a[N];
vector<int> g[M];
bool flag;
vector<int> ans;
bool vis[N]; void dfs(int p)
{
if (ans.size() == m)
{
for (int i = 0; i < ans.size(); ++i)
cout << ans[i] << "\n "[i < ans.size() - 1];
flag = true;
return;
}
if (flag)
return;
for (int i = 1; i <= m; ++i)
{
if (vis[i])
continue;
bool ok = true;
for (int j = 0; j < g[i].size(); ++j)
{
if (g[i][j] != a[p + j])
{
ok = false;
break;
}
}
if (ok)
{
vis[i] = true;
ans.push_back(i);
dfs(p + g[i].size() - 1);
if (flag)
return;
vis[i] = false;
ans.pop_back();
}
}
} void solve()
{
cin >> n;
for (int i = 1; i <= n; ++i)
cin >> a[i];
cin >> m;
for (int i = 1; i <= m; ++i)
{
int k;
cin >> k;
for (int j = 1; j <= k; ++j)
{
int x;
cin >> x;
g[i].push_back(x);
}
}
dfs(1);
}
signed main(void)
{
Zeoy;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}

森森旅游

有\(n\)座城市和\(m\)条路,每个城市可以用\(1\)元现金换\(a_i\)的旅游金,我们每次经过一条路只能选择支付现金\(c\)元或旅游金\(d\)元,但不能混用;现在我们需要从\(1\)号城市前往城市\(n\),我们需要在途中的某个城市\(j\)将所有剩余现金全部换成旅游金,也就是说,在到城市\(j\)之前我们只能用现金支付,过了城市\(j\)之后我们只能用旅游金支付;

现在有\(q\)次询问,每次询问改变一个城市的汇率,询问你至少带多少现金能够从1号城市到n号城市,每次询问在前一次询问的基础上改变

题解:最短路\(dij\) + 反向建图 + \(multiset\)维护最小值 \(O(nlogn)\)

我们可以先跑一次\(dij\)求出城市1到其他城市的最少现金,然后反向建图,求出\(n\)号城市到其他城市的最少旅游金,这样对于任意可达一个城市\(k\)来说我们就知道在该城市换旅游金最终需要带多少现金

根据题意该题无法离线,所以我们考虑动态维护每个可达城市中在该城市换旅游金最终需要带现金的最小值,使用\(multiset/map\)维护即可

注意:只有城市\(1\)和城市\(n\)都可达的城市才需要维护,否则不计入答案

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 1e5 + 10, M = 4e5 + 10; int n, m, q;
int a[N];
int dis1[N], dis2[N];
int vis[N]; struct node
{
int u, c, d;
};
vector<node> g[N], G[N]; void dij1(int st)
{
for (int i = 1; i <= n; ++i)
vis[i] = 0, dis1[i] = INF;
priority_queue<pii, vector<pii>, greater<pii>> q;
dis1[st] = 0;
q.push({dis1[st], st});
while (q.size())
{
int u = q.top().second;
q.pop();
if (vis[u])
continue;
vis[u] = 1;
for (auto [v, c, d] : g[u])
{
if (dis1[v] > dis1[u] + c)
{
dis1[v] = dis1[u] + c;
q.push({dis1[v], v});
}
}
}
} void dij2(int st)
{
for (int i = 1; i <= n; ++i)
vis[i] = 0, dis2[i] = INF;
priority_queue<pii, vector<pii>, greater<pii>> q;
dis2[st] = 0;
q.push({dis2[st], st});
while (q.size())
{
int u = q.top().second;
q.pop();
if (vis[u])
continue;
vis[u] = 1;
for (auto [v, c, d] : G[u])
{
if (dis2[v] > dis2[u] + d)
{
dis2[v] = dis2[u] + d;
q.push({dis2[v], v});
}
}
}
} multiset<int> st; void solve()
{
cin >> n >> m >> q;
for (int i = 1, u, v, c, d; i <= m; ++i)
{
cin >> u >> v >> c >> d;
if (v == u)
continue;
g[u].push_back({v, c, d});
G[v].push_back({u, c, d});
}
dij1(1);
dij2(n);
for (int i = 1; i <= n; ++i)
cin >> a[i];
for (int i = 1; i <= n; ++i)
if (dis1[i] != INF && dis2[i] != INF)
st.insert(dis1[i] + (int)(ceil(1.0 * dis2[i] / a[i])));
while (q--)
{
int x, val;
cin >> x >> val;
if (dis1[x] != INF && dis2[x] != INF)
{
auto it = st.lower_bound(dis1[x] + (int)(ceil(1.0 * dis2[x] / a[x])));
st.erase(it);
a[x] = val;
st.insert(dis1[x] + (int)(ceil(1.0 * dis2[x] / a[x])));
}
cout << *(st.begin()) << endl;
}
}
signed main(void)
{
Zeoy;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}

随机推荐

  1. Playwright 源码 BrowserType

    playwright-java 的 Browser.BrowserContext.Page 挺好理解的,唯独这厮,就有一丢丢 -- package com.microsoft.playwright; ...

  2. 小忙半个月搞个CKA,可还行,搞完后发现自己被割韭菜了

  3. 携手华为云WeLink,合合信息旗下名片全能王推动人脉管理数智化升级

    名片是商务场景中信息传递的重要载体.在无纸化办公日益兴盛的当下,数字名片逐渐被广大职场人士接受,成为商务交流的新方式.近期,合合信息旗下名片全能王与华为云WeLink联合研发,升级数字名片" ...

  4. SQL Server – Concurrency 并发控制

    前言 以前写过相关的, 但这篇主要讲一下概念. 帮助理解 Entity Framework with MySQL 学习笔记一(乐观并发) Asp.net core 学习笔记 ( ef core tra ...

  5. EF Core – 冷知识

    Add vs AddAsync 参考: .NET 5 REST API Tutorial AddAsync() vs Add() in EF Core EF Core's AddAsync v. Ad ...

  6. 全网最适合入门的面向对象编程教程:49 Python函数方法与接口-函数与方法的区别和lamda匿名函数

    全网最适合入门的面向对象编程教程:49 Python 函数方法与接口-函数与方法的区别和 lamda 匿名函数 摘要: 在 Python 中,函数和方法都是代码的基本单元,用于封装和执行特定的任务:它 ...

  7. CF228E 题解

    CF228E 题解 题目简述 给定一个 \(n\) 个点,\(m\) 条边的无向图,每条边都为 \(0\) 或 \(1\),可以进行若干次操作,与此点相连的所有点权值取反,求一种方案使得所有边都变为 ...

  8. C++11新初始化方法 使用{}初始化变量

    列表初始化 在C++11及以后的版本中,使用{}来初始化变量是一种新的初始化方法,称为列表初始化(List Initialization).这种初始化方法可以用来初始化内置类型.自定义类型以及聚合类型 ...

  9. 学好QT框架之后可以做什么工作?QT技术框架现代化行业大型复杂应用的经典成功案例

    简介 本文粗略的介绍了QT框架的软件开发技术生态体系的全球影响力:QT框架在文字办公领域.CAD三维图形领域.Linux操作系统领域.物联网领域.汽车电子领域以及数字医疗领域等现代化行业的大型复杂应用 ...

  10. 好文分享 | 记一次Oracle12c数据库SQL短暂缓慢问题分析

    本文为墨天轮社区作者 张sir 原创作品,记录了日常运维Oracle数据库过程中遇到的一个慢SQL问题的解决.优化过程,文章内容全面具体.分析到位,且含有经验总结,分享给各位. 问题现象 这次出问题的 ...