Atcoder ABC276 A-E

比赛传送门

A - Rightmost

求字符串中最后一次出现 a a a 的位置,若没有输出 − 1 -1 1

不讲。

#include<bits/stdc++.h>
using namespace std;
string s;
int ans=-1;
int main(){
	cin>>s;
	for(int i=0;i<s.size();++i) if(s[i]=='a') ans=i+1;
	cout<<ans<<endl;
	return 0;
}

B - Adjacency List

给定无向图,求每个与每个点相邻的点有多少,并从小到大输出点的编号。

邻接表 + + + 排序,不讲。

#include<bits/stdc++.h>
using namespace std;
int n,m,a[100010];
vector<int>w[100010];
int main(){
	cin>>n>>m;
	for(int i=1;i<=m;++i){
		int u,v;
		cin>>u>>v;
		w[u].push_back(v);
		w[v].push_back(u);
	}
	for(int i=1;i<=n;++i){
		int siz=w[i].size();
		cout<<siz<<' ';
		for(int j=1;j<=siz;++j) a[j]=w[i][j-1];
		sort(a+1,a+siz+1);
		for(int j=1;j<=siz;++j) cout<<a[j]<<' ';
		cout<<endl;
	}
	return 0;
}

C - Previous Permutation

给定 1 1 1 , , , 2 2 2 . . . ... ... n n n 的某种排列,求按字典序大小的上一个排列。

题目就是答案, S T L STL STL 自带函数 p r e v prev prev_ p e r m u t a t i o n permutation permutation ,解决。

#include<bits/stdc++.h>
using namespace std;
int n,a[110];
int main(){
	cin>>n;
	for(int i=1;i<=n;++i) cin>>a[i];
	prev_permutation(a+1,a+n+1);
	for(int i=1;i<=n;++i) cout<<a[i]<<' ';
	cout<<endl;
	return 0;
}

D - Divide by 2 or 3

给定一个数组,将每个数除以 2 2 2 3 3 3 任意多次,使得最后所有数都相同。求最小操作数。

显然,要使操作数最少,最后剩下的数也要是所有情况中最大的(否则,可以少除一次 2 2 2 3 3 3 )。于是,可以先求出所有数的最大公约数,然后将最大公约数一直除以 2 2 2 3 3 3 ,最后根据剩下的数求操作次数。算法复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

#include<bits/stdc++.h>
using namespace std;
int n,a[1010],ag,ans=0;
int gcd(int u,int v){
	return v?gcd(v,u%v):u;
}
int main(){
	cin>>n;
	for(int i=1;i<=n;++i){
		cin>>a[i];
		if(i==1) ag=a[i];
		else ag=gcd(ag,a[i]);
	}
	for(int i=1;i<=n;++i){
		int gd=a[i]/ag;
		while(!(gd%2)) gd/=2,ans++;
		while(!(gd%3)) gd/=3,ans++;
		if(gd!=1){
			cout<<-1<<endl;
			return 0;
		}
	}
	cout<<ans<<endl;
	return 0;
}

E - Round Trip

有一个迷宫,从某一点出发,不重复经过任何点走一条长度大于等于 4 4 4 的路径并回到原点,问是否存在这样的路径。

一,骗分,期望得分 50 50 50

二,正经的分析。

首先,如果存在这样的路径,其长度一定大于等于 4 4 4 (显而易见的)。

那么,我们只需要考虑,是否能找到一条从起点出发的路径,使得这条路径构成了一个环。

其实,如果把起点挖掉,此题相当于从起点旁边的四个点(也可能 ≤ 3 \le 3 3 个)出发,能否到达起点。但是要排除一步到位的情况,即直接回到起点。为了解决这个问题,我们不妨将这四个点再扩散一次,即从起点旁边的点的旁边的点(视为起点)出发,不经过扩散到它的起点旁边的点而到达起点(视为终点),这样就是一条合法路径。

#include<bits/stdc++.h>
using namespace std;
int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
struct nod{
	int x,y;
};
queue<nod>q;
int n,m,sx,sy;
string cins;
bool check(int idx,int idy){//检查超出边界用的,方便一点
	if(idx<1||idy<1||idx>n||idy>m) return 0;
	return 1;
}
int main(){
	cin>>n>>m;
	char c[n+10][m+10];
	bool vh[n+10][m+10];
	for(int i=1;i<=n;++i){
		cin>>cins;
		for(int j=1;j<=m;++j){
			c[i][j]=cins[j-1];
			if(c[i][j]=='S') sx=i,sy=j;
		}
	}
	for(int i=0;i<4;++i){
		int nx=sx+dx[i],ny=sy+dy[i];//一次扩散
		if(!check(nx,ny)||c[nx][ny]=='#') continue;
		for(int j=0;j<4;++j){
			int inx=nx+dx[j],iny=ny+dy[j];//二次扩散
			if(!check(inx,iny)||c[inx][iny]=='#') continue;
			if(inx!=sx||iny!=sy){//合法的起点
				memset(vh,0,sizeof(vh));
				vh[nx][ny]=1;
				q.push(nod{inx,iny});
				while(!q.empty()){//宽搜以判断能否到达
					nod now=q.front();
					q.pop();
					if(now.x==sx&&now.y==sy){
						cout<<"Yes"<<endl;
						return 0;
					}
					if(vh[now.x][now.y]) continue;
					vh[now.x][now.y]=1;
					//cout<<now.x<<' '<<now.y<<endl;
					for(int l=0;l<4;++l){
						int ntx=now.x+dx[l],nty=now.y+dy[l];
						if(!check(ntx,nty)||c[ntx][nty]=='#') continue;
						q.push(nod{ntx,nty});
					}
				}
			}
		}
	}
	cout<<"No"<<endl;
	return 0;
}

算法复杂度 O ( H × W ) O(H\times W) O(H×W)

F F F 题期望,不会。
G G G 题打的是 O ( n m 2 ) O(nm^2) O(nm2) 算法,后来想出 O ( n m ) O(nm) O(nm) 算法,没打,但还是超时。
E x Ex Ex 不用看,不会。

用时 44 : 30 + 5 m i n 44:30+5min 44:30+5min 1500 1500 1500 分, 986 986 986 名。

总结:
S T L STL STL 是个好东西。
代码实现能力有待提高。
S T L STL STL 自带数据结构要熟练运用。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值