病毒溯源

给定一棵树,树上有\(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. Angular Material 18+ 高级教程 – CDK Drag and Drop

    前言 CDK Drag and Drop 和 CDK Scrolling 都是在 Angular Material v7 中推出的. 它们有一个巧妙的共同点,那就是与 Material Design ...

  2. HTML – 冷知识

    Void Elements 需要 end slash? 这些是 void elements, 它们没有 end tag, 也没有 content. 至于关闭时是 ends with > 还是 / ...

  3. 记一次 .NET某上位机视觉程序 卡死分析

    一:背景 1. 讲故事 前段时间有位朋友找到我,说他的窗体程序在客户这边出现了卡死,让我帮忙看下怎么回事?dump也生成了,既然有dump了那就上 windbg 分析吧. 二:WinDbg 分析 1. ...

  4. SpringBoot——简介&&入门

    SpringBoot 简介 SpringBoot是由Pivotal团队提供的全新框架,其设计目的是用来简化Spring应用的初始搭建以及开发过程 起步依赖 starter:SpringBoot中常见的 ...

  5. HTTP——响应数据格式

    HTTP响应数据格式    状态码分类:    常见的状态响应码:      

  6. 信创环境经典版SuerMap iManager ARM版部署流程

    一.环境 操作系统:银河麒麟kylin V10 CPU:鲲鹏920 SuperMap iManager 10.2.1 硬件:4H32G机器 磁盘分区格式建议如下(请严格按照如下,减少后期有用/目录资源 ...

  7. Windows右下角时间显示具体星期

    事件起因: 有时候脑子不清楚,过着过着就会忘记今天是星期几,错过一些重要事情,于是乎就想看看Windows右下角能不能显示到具体星期,果然在查了资料之后这个需求可以达成 解决办法: 控制面板 - 日期 ...

  8. 安装mysql5.7报错启动失败(3534)的处理

    一 ,在官网下载好了mysql5.7之后,解压到对应的文件的夹下 二, 在cmd中进入到mysql下单bin目录下,一定要是管理员权限,执行mysqld --initialize 命令,会看到根目录下 ...

  9. 批量读取nii文件的shape

    import SimpleITK as sitk from glob import glob import os path = glob(r"D:\MyData\date\*") ...

  10. OOOPS:零样本实现360度开放全景分割,已开源 | ECCV'24

    全景图像捕捉360°的视场(FoV),包含了对场景理解至关重要的全向空间信息.然而,获取足够的训练用密集标注全景图不仅成本高昂,而且在封闭词汇设置下训练模型时也受到应用限制.为了解决这个问题,论文定义 ...