[题解]AtCoder Beginner Contest 416(ABC416) A~E

补题中~

A - Vacation Validation

枚举判定。

时间复杂度\(O(n)\)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
string s;
int n,l,r;
bool solve(){
	for(int i=l;i<=r;i++) if(s[i]=='x') return 0;
	return 1;
}
signed main(){
	cin>>n>>l>>r>>s;
	s=' '+s;
	cout<<(solve()?"Yes\n":"No\n");
	return 0;
}

B - 1D Akari

策略就是对于每一个.的连续段,选且仅选取其中一位置为o

时间复杂度\(O(n)\)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
string s;
bool v=1;
signed main(){
	cin>>s;
	for(char i:s){
		if(i=='.'){
			if(v) cout<<"o",v=0;
			else cout<<".";
		}else{
			cout<<"#";
			v=1;
		}
	}
	return 0;
}

C - Concat (X-th)

暴力枚举\(K^N\)种选择,然后nth_element或者排序来求第\(x\)小。

时间复杂度\(O(K^N\times N)\)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,k,x,idx,a[15];
string s[15],t[100010];
void dfs(int pos){
	if(pos>k){
		idx++;
		for(int i=1;i<=k;i++) t[idx]+=s[a[i]];
		return;
	}
	for(int i=0;i<n;i++){
		a[pos]=i;
		dfs(pos+1);
	}
}
signed main(){
	cin>>n>>k>>x;
	for(int i=0;i<n;i++) cin>>s[i];
	dfs(1);
	sort(t+1,t+1+idx);
	cout<<t[x]<<"\n";
	return 0;
}

D - Match, Mod, Minimize 2

据题意,\(A_i,B_i<M\)

所以对于我们重排的序列,如果记答案初始为\(\sum\limits_{i=1}^n A_i+B_i\),那么如果\(A_i+B_i\ge M\)则额外产生\(-M\)的贡献,否则不产生贡献。

所以我们是要让\(A_i+B_i\ge M\)的数量尽可能多。

因此我们将\(A,B\)排序,两个指针\(p_1,p_2\)分别指向\(A\)的最小值、\(B\)的最大值,匹配成功则都移动,并答案\(-M\),否则仅\(p_1\)移动。

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e5+10;
int t,n,m,a[N],b[N];
signed main(){
	cin>>t;
	while(t--){
		cin>>n>>m;
		int ans=0;
		for(int i=1;i<=n;i++) cin>>a[i],ans+=a[i];
		for(int i=1;i<=n;i++) cin>>b[i],ans+=b[i];
		sort(a+1,a+1+n),sort(b+1,b+1+n);
		for(int i=1,j=n;i<=n;i++)
			if(a[i]+b[j]>=m) ans-=m,j--;
		cout<<ans<<"\n";
	}
	return 0;
}

E - Development

看到\(n\)的范围,想到使用Floyd求解,\(f[i][j]\)\(i,j\)间的最短时间。

询问操作直接对着\(f[][]\)统计就行了。

加边操作也很好实现,每次加边\(O(n^2)\)地利用这条边重新松弛一遍即可。

再考虑建机场的操作。首先想到每建一个机场就和其他机场之间连一条权值为\(T\)的边,然后依次松弛。然而这样是\(O(n^3)\)的,无法接受。

但是这道题有一个很好的特性,就是机场之间构成了一个团(完全子图),意味着任意两个机场之间可以自由来往。所以两点之间的最短路,最多只能坐一次飞机。因为多次飞机一定可以用一次飞机上位替代。

因此我们重新定义\(f\)为不坐飞机的最短路,用\(g[i]\)表示离\(i\)最近的机场的距离,输出\((i,j)\)的答案时,和\(g[i]+g[j]+T\)取一次\(\min\)即可。

时间复杂度\(O(n^3+n^2q)\)

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=501;
int n,m,k,t,q,f[N][N],g[N];
bitset<N> is;
void ap(int u){//在u点建机场
	is[u]=1;
	for(int i=1;i<=n;i++){
		g[i]=min(g[i],f[i][u]);
	}
}
signed main(){
	cin>>n>>m;
	memset(f,0x3f,sizeof f),memset(g,0x3f,sizeof g);
	for(int i=1,u,v,w;i<=m;i++){
		cin>>u>>v>>w;
		f[u][v]=f[v][u]=min(f[u][v],w);
	}
	for(int i=1;i<=n;i++) f[i][i]=0;
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
			}
		}
	}
	cin>>k>>t;
	for(int i=1,u;i<=k;i++) cin>>u,ap(u);
	cin>>q;
	int op,x,y,z;
	while(q--){
		cin>>op;
		if(op==1){
			cin>>x>>y>>z;
			f[x][y]=f[y][x]=min(f[x][y],z);
			for(int i=1;i<=n;i++){
				for(int j=1;j<=n;j++){
					f[i][j]=min({f[i][j],f[i][x]+f[y][j]+z,f[j][x]+f[y][i]+z});
					if(is[j]) g[i]=min(g[i],f[i][j]);
				}
			}
		}else if(op==2){
			cin>>x;
			ap(x);
		}else{
			int ans=0,s;
			for(int i=1;i<=n;i++){
				for(int j=1;j<=n;j++){
					if((s=min(f[i][j],g[i]+g[j]+t))!=f[0][0]) ans+=s;
				}
			}
			cout<<ans<<"\n";
		}
	}
	return 0;
}

官方题解的思路是额外创建一个\(0\)号节点,任意机场到\(0\)号节点有一条权值为\(T\)的边,\(0\)号节点到任意机场有一条权值为\(0\)的边。这样建一个机场就相当于两次加边操作了。

F - Paint Tree 2

G - Concat (1st)

posted @ 2025-07-27 11:08  Sinktank  阅读(301)  评论(0)    收藏  举报
★CLICK FOR MORE INFO★ TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2025 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.