AtCoder Beginner Contest 451(ABC451)

A - illegal

判一下字符串长度是否为\(5\)的倍数即可。

点击查看代码
//草扎的精神,从此万寿无疆。
#include<bits/stdc++.h>

using namespace std;

signed main(){
	
	string s;
	cin >> s;
	int n = s.length();
	
	if(n%5) cout << "No";
	else cout << "Yes";
	
	return 0;
	
}

B - Personnel Change

算一下一开始每个部门有多少人,更换后每个部门有多少人,有后者减前者就是答案。

点击查看代码
//草扎的精神,从此万寿无疆。
#include<bits/stdc++.h>

using namespace std;

int n,m;
int gs[105];
int fs[105];

signed main(){
	
	cin >> n >> m;
	for(int i = 1;i <= n;++ i){
		int a,b;
		cin >> a >> b;
		gs[a]++;fs[b]++;
	}
	
	for(int i = 1;i <= m;++ i)
		cout << fs[i]-gs[i] << '\n';
	
	return 0;
	
}

C - Understory

用一个小根堆来存储,每次加入的时候就把这个高度加入,每次删除的时候就不断取出堆顶知道堆顶元素大于\(h\)

点击查看代码
//草扎的精神,从此万寿无疆。
#include<bits/stdc++.h>

using namespace std;

int n;
priority_queue<int,vector<int>,greater<int> > q;

signed main(){
	
	cin >> n;
	while(n--){
		int op,h;
		cin >> op >> h;
		if(op == 1) q.push(h);
		else{
			while(!q.empty()&&q.top() <= h)
				q.pop();
		}
		cout << q.size() << '\n';
	}
	
	return 0;
	
}

D - Concat Power of 2

观察样例3可得,\(10^9\)以内的好整数大概在\(10^6\)个左右。
首先把\(10^9\)以内的所有\(2\)的幂都找出来存下来,然后考虑从\(0\)开始\(dfs\),每次如果这个数小于\(10^9\),那么就往这个数后面加上一个\(2\)的幂,继续\(dfs\),直到这个数大于了\(10^9\),就回溯。
\(dfs\)的过程中把\(dfs\)到的所有数加入一个\(vector\),最后排一下序,取出这个\(vector\)的第\(n\)小即可。要注意不要把\(0\)加进去,也不要重复加。
有的人可能觉得没有重复加的问题,但看一下\(164\)可以发现,它既可以是\(1,64\),也可以是\(16,4\)

点击查看代码
//草扎的精神,从此万寿无疆。
#include<bits/stdc++.h>

#define int long long

using namespace std;

int n;
int bas[35],bcnt;
vector<int> s;
map<int,int> mp;

int lianjie(int x,int y){
	int t = y;
	while(t){
		x *= 10;
		t /= 10;
	}
	return x+y;
}

void dfs(int x){
	if(x <= 1e9){
		if(x != 0){
			if(!mp[x]) s.push_back(x);
			mp[x] = 1;
		}
	}
	else return;
	for(int i = 1;i <= bcnt;++ i)
		dfs(lianjie(x,bas[i]));
}

signed main(){
	
	cin >> n;
	
	bas[1] = 1;
	for(bcnt = 2;;++ bcnt){
		bas[bcnt] = bas[bcnt-1]*2;
		if(bas[bcnt] > 1e9){
			bcnt--;
			break;
		}
	}
	
	dfs(0);
	sort(s.begin(),s.end());
	cout << s[n-1];
	
	return 0;
	
}

E - Tree Distance

首先我们知道,如果对于任意的\(i\)\(j\)\(k\),如果有\(a_{i,k}+a_{k,j} < a_{i,j}\),那么一定构不成一棵树。

为啥? 考虑两种情况:

1.\(k\)\(i\)\(j\)的路径上,那么一定是等号;

2.\(k\)不在\(i\)\(j\)的路径上,那么一定是先走到某个点,然后走到\(k\),再走回这个点,最后走到\(j\),那么一定是大于号。

所以如果是小于,就一定构不成一棵树。

可是这样显然不行,我们无法枚举\(n^3\),而且就算满足这个条件,也不一定能构成树。
那么我们先假定满足了这个条件(嘻嘻),那么就剩下了\(\forall i,j,k\)\(a_{i,k}+a_{k,j} \geq a_{i,j}\)的情况。
所以我们想要构造出最可能有解的一棵树,然后判断一下这棵树是否符合条件(判断就\(O(n^2)\)判就行了)。
现在我们规定对于下面说的所有的\(i,j,k\),都是\(k\)\(i\)\(j\)的路径上的,那么我们就是想要满足\(a_{i,k}+a_{k,j} = a_{i,j}\)这个条件。
那么我们现在是有\(a_{i,k}+a_{k,j} \geq a_{i,j}\)的,那么也就是\(a_{i,k}+a_{k,j}\)最小的时候才有可能满足条件。由于\(k\)\(i\)\(j\)的路径上,那么这个式子就相当于\(i\)\(j\)的距离(注意这里不能说是\(a_{i,j}\)因为我们不确定是否能满足条件),那么想要任意两个点间的距离尽可能小,又是要生成一棵树,那么就是最小生成树了。(想一下为什么,树上两点间的路径是固定的)
这是再来解答为啥可以假定满足了\(a_{i,k}+a_{k,j} \geq a_{i,j}\),因为我们生成出了一棵树了,那么如果不满足这个基本条件,那么在最后判断的时候一定会被判掉,所以我们不用担心这个条件。

点击查看代码
//草扎的精神,从此万寿无疆。
#include<bits/stdc++.h>

#define int long long

using namespace std;

int n;
struct edge{
	int u,v,w;
}e[4500005];
int ecnt;
int a[3005][3005];

bool cmp(edge a,edge b){
	return a.w < b.w;
}

int fa[3005];

int find(int x){
	if(x == fa[x]) return x;
	return fa[x] = find(fa[x]);
}

vector<pair<int,int> > ed[3005];

int dis[3005];
int st[3005][15];
int dep[3005];

void dfs(int x,int fa){
	dep[x] = dep[fa]+1;
	st[x][0] = fa;
	for(int i = 1;i <= 13;++ i)
		st[x][i] = st[st[x][i-1]][i-1];
	for(auto [y,w]:ed[x]){
		if(y == fa) continue;
		dis[y] = dis[x]+w;
		dfs(y,x);
	}
}

int lca(int x,int y){
	if(dep[x] < dep[y]) swap(x,y);
	for(int i = 13;i >= 0;-- i)
		if(dep[st[x][i]] >= dep[y])
			x = st[x][i];
	if(x == y) return x;
	for(int i = 13;i >= 0;-- i)
		if(st[x][i] != st[y][i])
			x = st[x][i],y = st[y][i];
	return st[x][0];
}

signed main(){
	
	cin >> n;
	
	for(int i = 1;i < n;++ i){
		fa[i] = i;
		for(int j = i+1;j <= n;++ j){
			cin >> a[i][j];
			e[++ecnt] = {i,j,a[i][j]};
		}
	}
	fa[n] = n;
	
	sort(e+1,e+1+ecnt,cmp);
	
	for(int i = 1;i <= ecnt;++ i){
		int u = e[i].u;
		int v = e[i].v;
		int w = e[i].w;
		if(find(u) == find(v)) continue;
		fa[find(u)] = find(v);
		ed[u].push_back({v,w});
		ed[v].push_back({u,w});
	}
	
	dfs(1,0);
	
	for(int i = 1;i < n;++ i){
		for(int j = i+1;j <= n;++ j){
			if(a[i][j] != dis[i]+dis[j]-2*dis[lca(i,j)]){
				cout << "No";
				return 0;
			}
		}
	}
	
	cout << "Yes";
	
	return 0;
	
}

点击查看代码
//草扎的精神,从此万寿无疆。
posted @ 2026-03-29 09:39  u_uICLMFu_uX  阅读(57)  评论(0)    收藏  举报