病毒溯源

给定一棵树,树上有\(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. 几步轻松定制私人AI助手

    这两年大模型的发展持续火热,以至于许多资本和学者认为AI出现了泡沫,根本原因还是因为大模型目前还没有出现能够结合行业切实落地的应用. 我才不关注泡沫不泡沫呢,我只关注大模型能给我带来哪些帮助即可.大模 ...

  2. AGC007F 题解

    题意 给定两个长为 \(n\) 的字符串 \(S, T\),求最少进行多少次操作才能使 \(S = T\). 一次操作定义为:对于 \(i = 1, 2, .. n\),令第 \(i\) 位为操作后的 ...

  3. 1 月 25 日见|Flutter Forward 活动日程表正式发布!

    2023 年 1 月 25 日 (正月初四),我们将在肯尼亚首都内罗毕举办 Flutter Forward 大会,并同时开启线上直播.本次活动将展示最新的 Flutter 技术更新,包括一个主题演讲以 ...

  4. 使用 Flutter 加速应用开发

    作者 / Larry McKenzie 本文由 eBay 技术负责人 Larry Mckenzie 和 Corey Sprague 撰写.您可以收听他们在 Google Apps, Games &am ...

  5. Vite2 如何设置打包后文件名

    vite.config.js build: { rollupOptions: { output: { entryFileNames: `assets/[name].${timestamp}.js`, ...

  6. Laravel视图共享数据

    Laravel视图共享数据 最近在用lavavel过程中想实现公共头部尾部需要的配置数据在所有的页面中都可以使用,便查看了官方文档,在此做一个总结: 一. 修改 ComposerServiceProv ...

  7. .NET 代码混淆工具-JIEJIE.NET

    前言 JIEJIE.NET是一款强大的开源.NET程序集混淆工具.它利用深度加密技术和多样化的混淆策略,有效地保护了.NET软件的版权和源代码安全,防止未经授权的访问和篡改. 项目介绍 JIEJIE. ...

  8. 理解 keep-alive

    keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,避免重新渲染 : 对应两个钩子函数 activated 和 deactivated ,当组件被激活时,触发钩子函数 act ...

  9. npm/yarn是什么,他们的区别 ? & node.js 又是个啥

    是什么? npm(全称Node Package Manager,即 node 包管理器) ,是Node.js默认的包管理系统 ; 区别: yarn 的速度开快,因为yarn 是并行安装,npm是串行安 ...

  10. kotlin集合——>迭代器、区间与数列

    1.迭代器 对于遍历集合元素,Kotlin 标准库支持 迭代器 的常用机制⸺对象可按顺序提供对元素的访问权限,而 不会暴露集合的底层结构.当需要逐个处理集合的所有元素(例如打印值或对其进行类似更新)时 ...