[题解]AtCoder Beginner Contest 398(ABC398) A~F

A - Doors in the Center

  • 如果\(n\)为奇数,就依次输出\(\frac{n-1}{2}\)-\(1\)=\(\frac{n-1}{2}\)-
  • 如果\(n\)为偶数,就依次输出\(\frac{n}{2}-1\)-\(2\)=\(\frac{n}{2}-1\)-

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

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n;
signed main(){
	cin>>n;
	if(n&1){
		for(int i=1;i<=n/2;i++) cout<<"-";
		cout<<"=";
		for(int i=1;i<=n/2;i++) cout<<"-";
	}else{
		for(int i=1;i<n/2;i++) cout<<"-";
		cout<<"==";
		for(int i=1;i<n/2;i++) cout<<"-";
	}
	return 0;
}

B - Full House 3

统计每个值出现的次数,输出Yes\(\iff\)最大次数\(\ge 3\)且次大次数\(\ge 2\)

代码为了方便对桶数组进行了排序,时间复杂度为\(O(n+V\log V)\)。也可以做到\(O(n)\)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int b[14];
signed main(){
	for(int i=0,a;i<7;i++) cin>>a,b[a]++;
	sort(b+1,b+1+13);
	if(b[13]>=3&&b[12]>=2) cout<<"Yes\n";
	else cout<<"No\n";
	return 0;
}

C - Uniqueness

可以用map等数据结构作为桶,或者离散化后直接用数组作为桶。

统计所有出现次数为\(1\)\(a_i\),将最大的\(a_i\)所对应的\(i\)记录并输出即可。

代码时间复杂度\(O(n)\)。如果用map或者离散化则是\(O(n\log n)\)

点击查看代码
#include<bits/stdc++.h>
#define N 300010
using namespace std;
unordered_map<int,int> ma;
int n,a[N],maxx,maxpos=-1;
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i],ma[a[i]]++;
	for(int i=1;i<=n;i++){
		if(ma[a[i]]==1&&a[i]>=maxx){
			maxx=a[i],maxpos=i;
		}
	}
	cout<<maxpos;
	return 0;
}

D - Bonfire

让烟静止下来。

风向右吹,可以看做人和篝火同时向左走,且篝火在原来的位置留下了一团烟。其他方向同理。

这样一来烟就是静止不动的了。遍历每一个操作,同时用set记录篝火走过的每一个位置,如果某次操作后人走到了此前篝火曾走过的位置,就输出1

代码时间复杂度\(O(n\log n)\)。如果把下标压到一个整数里再用哈希表也可以做到\(O(n)\),不过没必要。

点击查看代码
#include<bits/stdc++.h>
#define N 200010
using namespace std;
int n,r,c,x,y;
string s;
set<pair<int,int>> vis;
signed main(){
	cin>>n>>r>>c>>s;
	vis.insert({0,0});
	for(char i:s){
		if(i=='N') x++,r++;
		else if(i=='S') x--,r--;
		else if(i=='E') y--,c--;
		else if(i=='W') y++,c++;
		vis.insert({x,y});
		cout<<vis.count({r,c});
	}
	return 0;
}

很有意思的思维题。

E - Tree Game

不难发现,最后游戏结束时,\(G\)一定变成了一个完全二分图。

由于所给的图是树,所以将它看做二分图时,两个组的节点是固定的。从而两人的总操作数也是固定的,即为\(x\times y-(n-1)\),其中\(x,y\)是两组的节点数。

如果\(x\times y-(n-1)\)为奇数则选择先手,否则选择后手。

接下来每次己方操作,就选一条对方没连过的边输出即可。

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

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define N 110
using namespace std;
int n,cntw;
bitset<N> vis[N];
bitset<N> col;
vector<int> G[N];
void dfs(int u,int fa){
	cntw+=col[u];
	for(int i:G[u]){
		if(i==fa) continue;
		col[i]=col[u]^1,dfs(i,u);
	}
}
signed main(){
	cin>>n;
	for(int i=1,u,v;i<n;i++){
		cin>>u>>v;
		G[u].emplace_back(v);
		G[v].emplace_back(u);
		vis[u][v]=1;
	}
	dfs(1,0);
	int t=cntw*(n-cntw)-(n-1),u,v;
	if(t&1){
		cout<<"First"<<endl;
	}else{
		cout<<"Second"<<endl;
		cin>>u>>v;
		if(u==-1) exit(0);
		vis[u][v]=1;
	}
	for(int i=1;i<n;i++){
		for(int j=i+1;j<=n;j++){
			if(!vis[i][j]&&col[i]!=col[j]){
				cout<<i<<" "<<j<<endl;
				cin>>u>>v;
				if(u==-1) exit(0);
				vis[u][v]=1;
			}
		}
	}
	return 0;
}

作为E实在有点水了。

F - ABCBA

当我们找到一个\(S\)的回文后缀,将这个后缀之前的东西翻转过来拼在\(S\)末尾,这样一个合法的回文串\(S'\)就构造成了。

为了使\(S'\)最短,我们要寻找\(S\)的最长回文后缀。

可以使用Manacher算法求解,不过我还不会,所以就用字符串哈希了(

求法比较自然,就是从大到小枚举回文长度,看该长度的后缀倒过来是否和原后缀相同。

两种求法时间复杂度均为\(O(n)\)

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define N 500010
#define B 131
using namespace std;
string s;
int n;
ull ds[N],dr[N],powb[N];
ull f(int l,int r){
	return ds[r]-ds[l-1]*powb[r-l+1];
}
ull fr(int l,int r){
	swap(l,r),l=n-l+1,r=n-r+1;
	return dr[r]-dr[l-1]*powb[r-l+1];
}
signed main(){
	powb[0]=1;
	for(int i=1;i<N;i++) powb[i]=powb[i-1]*B;
	cin>>s;
	n=s.size(),s=' '+s;
	for(int i=1;i<=n;i++) ds[i]=ds[i-1]*B+s[i];
	for(int i=1;i<=n;i++) dr[i]=dr[i-1]*B+s[n-i+1];
	int i;
	for(i=1;i<=n;i++){
		if(f(i,n)==fr(i,n)){
			for(char j:s) if(j!=' ') cout<<j;
			for(int j=i-1;j>=1;j--) cout<<s[j];
			break;
		}
	}
	return 0;
}

作为F实在有点水过头了……

而且放\(\bf O(n^2)\)暴力过了!?

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