提高组热身赛小计(非题目顺序)
T1商务旅行
题意
给定一棵 N 个结点的树,所有边的权值均为 1。从结点 1 出发,依次经过 M 个指定结点,求路径总长度的最小值。
思路
代码首先通过深度优先搜索(DFS)预处理出每个城镇的深度以及祖先信息(用于快速计算最近公共祖先),然后利用最近公共祖先(LCA)算法计算商人按给定顺序经过各个城镇时的最短路径总时间。
计算过程中,每两个连续城镇之间的最短路径长度通过它们的深度与它们 LCA 的深度计算得出(公式为:d[x] + d[y] - 2 * d[LCA(x,y)])
,最后将所有连续城镇间的路径长度累加,得到总的旅行时间。
这一实现适用于城镇以树结构连接的场景(无环,任意两城镇间有唯一路径),能高效处理较大规模的输入数据(城镇数达$ 3×10⁴$,经过的城镇数达$ 3×10⁵$)。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=30005;
int h[N],fa[N][25];
vector<int>G[N];
void dfs(int x,int f) {h[x]=h[f]+1;fa[x][0]=f;for(int i=1; i<=20; ++i){fa[x][i]=fa[fa[x][i-1]][i-1];}for(int y:G[x]) {if(y!=f)dfs(y,x);}
}
int LCA(int x,int y) {//倍增 if(x==y)return x;if(h[x]>h[y])swap(x,y);for(int i=20; i>=0; --i) {if(h[fa[y][i]]>=h[x]) {y=fa[y][i];}}if(x==y)return x;for(int i=20; i>=0; --i)if(fa[x][i]!=fa[y][i]) {x=fa[x][i];y=fa[y][i];}return fa[x][0];
}
int main() {ios::sync_with_stdio(0);cin.tie(0);int n;cin>>n;for(int i=1; i<n; ++i) {int a,b;cin>>a>>b;G[a].push_back(b);G[b].push_back(a);}dfs(1,0);int m;cin>>m;long long res=0;int rs;cin>>rs;for(int i=1; i<m; ++i) {int mw;cin>>mw;int ac=LCA(rs,mw);res+=h[rs]+h[mw]-2*h[ac];rs=mw;}cout<<res<<"\n";return 0;
}
T2无线传输
题意
给你一个字符串s1,它是由某个字符串s2不断自我连接形成的(保证至少重复 2 次)。但是字符串s2是不确定的,现在只想知道它的最短长度是多少。
思路
||经典的KMP算法q(≧▽≦q)推导发现:
设循环节的长度为x,那么kmp数组前x个都是0,后面kmp[x+n]=n
先求出kmp数组
答案实际就是len-kmp[len]
代码copy
#include <bits/stdc++.h>
#define N 1000111
using namespace std;
string a;
int k[N];
int main() {int n;cin>>n>>a;k[0]=0;k[1]=0;for(int i=1,ks=0;i<n;++i) {while(ks!=0&&a[i]!=a[ks]) {ks=k[ks];}if(a[i]==a[ks]) k[i+1]=++ks;else k[i+1]=0;}cout<<n-k[n];return 0;
}
T3鬼子进村
题意(李云龙)
给定一些操作,查找,删除,与重建,查找时求连通块长度
思路
数据结构:
数组 b[] 标记房子是否被摧毁(1 表示摧毁,0 表示正常)
栈 s[] 记录被摧毁房子的顺序(用于恢复操作)
变量 t 作为栈顶指针
核心逻辑:
- 对于 D x 操作:标记 x 号房子为摧毁状态,并将 x 入栈
- 对于 R 操作:从栈中取出最后一个被摧毁的房子,恢复其正常状态
- 对于 Q x 操作:
1. 寻找 x 左边最近的被摧毁房子(记为 l)
2.寻找 x 右边最近的被摧毁房子(记为 r)
若 x 本身被摧毁(此时 l 和 r 可能相等),则输出 0
否则,能到达的房子数量为 r - l - 1(即左右两个摧毁点之间的所有房子)
优势:
利用栈维护摧毁顺序,使得恢复操作(R)可以高效执行
通过遍历栈中元素来查找左右边界,思路直观
时间复杂度主要取决于查询操作中遍历栈的次数,在实际场景中基本能满足需求
- 例如样例中查询 4 号房子时:
左边最近的摧毁点是 3,右边最近的摧毁点是 5
因此能到达的房子是 4,共 1 个(对应第一次查询输出 1)
代码
#include<bits/stdc++.h>
#define N 500050
using namespace std;
int n,m;
int t,s[N];
bool b[N];
int main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n>>m;for(int i=1; i<=m; i++) {char op;cin>>op;if(op=='R') {b[s[t--]]=0;continue;}int a;cin>>a;if(op=='D') {b[a]=1;s[++t]=a;}if(op=='Q'){//二分求联通int l=0,r=n+1;for(int i=1; i<=t; i++) {if(s[i]<=a) l=max(s[i],l);if(s[i]>=a) r=min(s[i],r);}if(l==r) cout<<0<<'\n';else cout<<r-l-1<<'\n';}}
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/931250.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!