“蔚来杯“2022牛客暑期多校训练营3 题解

C题 Concatenation
思路:给出几个数字段,求能组成的字典序最小的字符串。用sort使得组合完的字符串序列字典序最小即可。

#include<bits/stdc++.h>
using namespace std;
const int N=2e6;
string s[N];
bool cmp(string a,string b){
    return a+b<b+a;
}
int n;
int main(){
    ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
    cin>>n;
    
    for(int i=0;i<n;i++){
        cin>>s[i];
    }
    sort(s,s+n,cmp);
    for(int i=0;i<n;i++)
        cout<<s[i];
}

A题 Ancestor
题意:给你两棵树A和B,点的编号从1到n,根结点是1,且每个点都有一个价值,现在给你k个点,选任意k-1个不同的点,分别求这些点在两颗树上的最近公共祖先fa, fb,问存在多少种情况满足A树上fa的价值大于B树上fb的价值。
思路:有一个结论是:求树上多个点的LCA的方法是求这些点在树上的dfs序的最小值的点和最大值的点的LCA。所以我们求出来两颗树的dfs序后,将k个点按照dfs序的大小来排序后,离线处理,再按照上面的结论进行计算就行。

#include<bits/stdc++.h>
#define pb push_back
using namespace std;
const int N=1e5+9;
int n,k,ans;
int a[N],v[N],f[N],g[N],st[N][21],d[N],p[N][2];
vector<int>e[N];
void dfs(int x,int fa){
	d[x]=d[fa]+1; st[x][0]=fa;
	for(int y:e[x])
		if(y!=fa)
			dfs(y,x);
}
void buildst(){
	for(int j=1;j<=20;j++)
		for(int i=1;i<=n;i++)
			st[i][j]=st[st[i][j-1]][j-1];
}
int LCA(int x,int y){
	if(d[x]<d[y]) swap(x,y);
	for(int i=20;i>=0;i--)
		if(d[st[x][i]]>=d[y])
			x=st[x][i];
	if(x==y) return x;
	for(int i=20;i>=0;i--)
		if(st[x][i]!=st[y][i])
			x=st[x][i],y=st[y][i];
	return st[x][0];
}
void work(int op){
	for(int i=1;i<=n;i++)
		cin>>v[i],e[i].clear();
	for(int i=2,x;i<=n;i++)
		cin>>x,e[x].pb(i);
	dfs(1,0); buildst();
	f[1]=a[1]; g[k]=a[k];
	for(int i=2;i<=k;i++)
		f[i]=LCA(f[i-1],a[i]);
	for(int i=k-1;i>=1;i--)
		g[i]=LCA(g[i+1],a[i]);
	f[0]=g[2]; g[k+1]=f[k-1];
	for(int i=1;i<=k;i++)
		p[i][op]=v[LCA(f[i-1],g[i+1])];
}
int main(){
	cin>>n>>k;
	for(int i=1;i<=k;i++)
		cin>>a[i];
	work(0); work(1);
	for(int i=1;i<=k;i++)
		ans+=(p[i][0]>p[i][1]);
	cout<<ans<<endl;
}

J题 Journey
题目:给你一个有向图,问能否选择一个起点,使得每个点和每条边都走且只走过一次。
思路:判断这个图是不是一条链。链的条件有一条:mn-1mn−1。这样约束起来就是树和环的组合(可能是一棵树加一个环)。再把入度和出度约束在0,1之间,这样就是链+环。然后通过入度为零的点就是起点,把整条链扫一遍,计算通过的节点个数,判断是否有环即可。

#include <bits/stdc++.h>
using namespace std;
struct inf{
public:
	int u;
	int v;
	int cst;
};
int main(){
	int n;scanf("%d",&n);
	vector<vector<int>> li(n+1,vector<int>(5));
	vector<vector<int>> ale(n+1,vector<int>(5));
	for(int i=1;i<=n;i++)
		for(int j=1;j<=4;j++)
			scanf("%d",&li[i][j]);
	int s1,s2,t1,t2;scanf("%d%d%d%d",&s1,&s2,&t1,&t2);
	deque<inf> que;
	que.push_front({s1,s2,0});
	int ans=2147483647;
	while(!que.empty()){
		inf info=que.front();que.pop_front();
		int u=info.u,v=info.v,cst=info.cst;
        if(u==t1&&v==t2)ans=min(ans,cst);
		int pos=0;
		for(int i=1;i<=4;i++)if(li[v][i]==u)pos=i;
		if(ale[v][pos]++)continue;
        que.push_front({v,li[v][pos%4+1],cst});
		for(int i=1;i<=4;i++){
			que.push_back({v,li[v][i],cst+(i==pos%4+1?0:1)});
		}
	}
	printf("%d",ans==2147483647?-1:ans);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值