Codeforces Round #648 (Div. 2)——ABCD题解

A. Matrix Game

传送门A. Matrix Game

题目:

在这里插入图片描述

测试样例:

输入样例:
4
2 2
0 0
0 0
2 2
0 0
0 1
2 3
1 0 1
1 1 0
3 3
1 0 0
0 0 0
1 0 0

输出样例:
Vivek
Ashish
Vivek
Ashish

Note
For the first case: One possible scenario could be: Ashish claims cell (1,1), Vivek then claims cell (2,2). Ashish can neither claim cell (1,2), nor cell (2,1) as cells (1,1) and (2,2) are already claimed. Thus Ashish loses. It can be shown that no matter what Ashish plays in this case, Vivek will win.
For the second case: Ashish claims cell (1,1), the only cell that can be claimed in the first move. After that Vivek has no moves left.
For the third case: Ashish cannot make a move, so Vivek wins.
For the fourth case: If Ashish claims cell (2,3), Vivek will have no moves left.

题目大意:

  有n*m的单元格,其中只包含0和1,1单元格的同行同列都是不可操作的。现在Ashish和Vivek在玩游戏,在可操作的地方将0替换成1。Ashish先开始游戏,当某人无法进行操作时,对方获胜。

思路:

  先标记给定单元格中的无法操作的行和列,然后对可操作的单元格进行操作,每次操作后标记相应的行和列不可操作。统计进行的操作次数,奇数次则Ashish赢,否则Vivek获胜(因为Ashish先手操作)。

AC代码:

#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
int a[55][55];
int vis1[55],vis2[55];
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		//多组样例
		memset(vis1,0,sizeof(vis1));
		memset(vis2,0,sizeof(vis2));
		int n,m;
		cin>>n>>m;
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
			{
				cin>>a[i][j];
				//如果为 1,标记行和列不可操作
				if(a[i][j]==1)
				{
					vis1[i]=1;
					vis2[j]=1;
				}
			}
		}
		int cnt=0;
		for(int i=1;i<=n;i++)
		{
			if(vis1[i]!=1)//行可以操作
			{
				for(int j=1;j<=m;j++)
				{
					if(vis2[j]!=1)//列可以操作
					{
						cnt++;
						vis1[i]=1;//标记行不可操作
						vis2[j]=1;//标记列不可操作
						break;
					}
				}
			}
		}
		if(cnt&1)
			cout<<"Ashish"<<endl;
		else
			cout<<"Vivek"<<endl;	
	}
	return 0;
}

B. Trouble Sort

传送门:B. Trouble Sort

题目:

在这里插入图片描述

测试样例:

输入样例:
5
4
10 20 20 30
0 1 0 1
3
3 1 2
0 1 1
4
2 2 4 8
1 1 1 1
3
5 15 4
0 0 0
4
20 10 100 50
1 0 0 1

输出样例:
Yes
Yes
Yes
No
Yes

Note
For the first case: The elements are already in sorted order.
For the second case: Ashish may first swap elements at positions 1 and 2, then swap elements at positions 2 and 3.
For the third case: The elements are already in sorted order.
For the fourth case: No swap operations may be performed as there is no pair of elements i and j such that bi≠bj. The elements cannot be sorted.
For the fifth case: Ashish may swap elements at positions 3 and 4, then elements at positions 1 and 2.

题目大意:

  T组测试样例,每组测试样例N个元素,每个元素有值和类型两个属性(第一行是值,第二行是类型)。可以选择不同类型的元素进行交换位置,问最终能否得到单调不降的值序列。

思路:

  如果原来的值序列本身不是有序的且所有的元素的类型相同,则不能得到单调不降的值序列,因为没有另一种类型的元素,无法交换。
  只要有元素的类型不同,就一定可以通过交换得到单调不降的值序列。

AC代码:

#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int value[505],type[505],temp[505];
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		int n;
		cin>>n;
		for(int i=0;i<n;i++)
		{
			cin>>value[i];
			temp[i]=value[i];
		}
		//两种类型个数
		int cnt1=0,cnt2=0;
		for(int i=0;i<n;i++)
		{
			cin>>type[i];
			if(type[i]==1)
				cnt1++;
			else
				cnt2++;
		}
		sort(temp,temp+n);
		int flag=1;
		//判断原值序列是否单调不降
		for(int i=0;i<n;i++)
		{
			if(value[i]!=temp[i])
			{
				flag=0;
				break;
			}
		}
		//如果原值序列不是单调不降且所有元素只有一种类型
		if(!flag&&((!cnt1&&cnt2)||(!cnt2&&cnt1)))
			cout<<"No"<<"\n";
		else
			cout<<"Yes"<<"\n";	
	}
	return 0;
}

C. Rotation Matching

传送门:C. Rotation Matching

题目:

在这里插入图片描述

测试样例:

输入样例1:
5
1 2 3 4 5
2 3 4 5 1
输出样例15

输入样例25
5 4 3 2 1
1 2 3 4 5
输出样例21

输入样例34
1 3 2 4
4 2 3 1
输出样例32

Note
For the first case: b can be shifted to the right by k=1. The resulting permutations will be {1,2,3,4,5} and {1,2,3,4,5}.
For the second case: The operation is not required. For all possible rotations of a and b, the number of matching pairs won’t exceed 1.
For the third case: b can be shifted to the left by k=1. The resulting permutations will be {1,3,2,4} and {2,3,1,4}. Positions 2 and 4 have matching pairs of elements. For all possible rotations of a and b, the number of matching pairs won’t exceed 2.

题目大意:

  给定两组数,每组N个。可以将一组数整体向左或者向右循环移动K个单位。问:移动后相同位置相同的最多有多少个。

思路:

  题中说了每个数字都不重复。则可以计算两组数中相同数的相对位置差并统计,最后找同位置差个数最多的即可。即如果有K个数位置差都是m,则同时移动m个单位就会有k个数能够相互对应,找最大的cnt[m]即可。

AC代码:

#include<iostream>
#include<cstring>
#define IOS ios::sync_with_stdio(false);
using namespace std;
const int MAXN=2e5+5;
int a[MAXN],b[MAXN],cnt[MAXN];
int main()
{
	IOS
	int n,k;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>k;
		//第一组数,数字 k 在 i 号位置
		a[k]=i;
	}
	for(int i=1;i<=n;i++)
	{
		cin>>k;
		//第二组数,数字 k 在 i 号位置
		b[k]=i;
	}	
	for(int i=1;i<=n;i++)
	{
		int temp=(n+a[i]-b[i])%n;//相对位置差
		cnt[temp]++;//统计 相对位置差为 temp 的个数
	}		
	int ans=0;
	for(int i=0;i<=n;i++)
		ans=max(ans,cnt[i]);
	cout<<ans<<"\n";
	return 0;
}

D. Solve The Maze

传送门:D. Solve The Maze

题目:

在这里插入图片描述

测试样例:

输入样例:
6
1 1
.
1 2
G.
2 2
#B
G.
2 3
G.#
B#.
3 3
#B.
#..
GG.
2 2
#B
B.

输出样例:
Yes
Yes
No
No
Yes
Yes

Note
For the first and second test cases, all conditions are already satisfied.
For the third test case, there is only one empty cell (2,2), and if it is replaced with a wall then the good person at (1,2) will not be able to escape.
For the fourth test case, the good person at (1,1) cannot escape.
For the fifth test case, Vivek can block the cells (2,3) and (2,2).
For the last test case, Vivek can block the destination cell (2,2).

题目大意:

  现在有n*m的迷宫,(n,m)是出口,在迷宫里 ’ . ’ 表示空,’ # ‘表示墙,’ G ‘表示好人,’ B '表示坏人。好人和坏人可以走上下左右四个方向,有墙的地方不能通过,可以将空的地方用墙堵起来阻碍通过。
  问:能否将某些空的地方堵上墙,使得所有的坏人无法逃出迷宫,而所有的好人都能逃出迷宫。

思路:

  如果坏人四周某个方向有好人就一定不行,因为坏人可以跟着好人出去。此时为"No"
  如果坏人四周有空地地方,就将空的地方换成墙来阻碍坏人通过(此时并不会因为都换成了墙而阻碍到好人,因为如果会阻碍到好人通过,则坏人也可以跟着好人通过)。
  当坏人四周的空都换成墙后(已经保证所有坏人出不去了):
    1、如果出口也被堵住了,且有好人在迷宫中,则好人也无法出去了。此时为"No"
    2、如果出口没被堵住,就判断能走出迷宫的好人和好人总数是否相等。相等即所有好人都可以出去为"Yes",否则是"No"。
  当搜索能走出迷宫好人数目时,因为所有好人有共同的出口,所以可以从出口开始搜索,加快搜索速度。

AC代码1(DFS):

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
int dir[4][2]={1,0,-1,0,0,1,0,-1};
char g[55][55];
bool vis[55][55];
int n,m;
int cnt=0,ans=0;
bool check(int x,int y)
{
	return (x>0&&y>0&&x<=n&&y<=m);
}
//需要剪枝,走过的路不再走,不恢复标记
void dfs(int x,int y)
{
	vis[x][y]=1;
	if(g[x][y]=='G')
		ans++;
	for(int i=0;i<4;i++)
	{
		int dx=x+dir[i][0];
		int dy=y+dir[i][1];
		if(check(dx,dy)&&!vis[dx][dy]&&g[dx][dy]!='#')
			dfs(dx,dy);
	}
}
void solve()
{
	ans=0;
	cnt=0;
	memset(vis,0,sizeof(vis));
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			cin>>g[i][j];
			if(g[i][j]=='G')//统计好人个数
				cnt++;
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(g[i][j]=='B')
			{
				for(int k=0;k<4;k++)
				{
					int dx=i+dir[k][0];
					int dy=j+dir[k][1];
					if(check(dx,dy))//四周
					{
						if(g[dx][dy]=='.')//堵墙
							g[dx][dy]='#';
						if(g[dx][dy]=='G')//坏人可以跟着好人走出去
						{
							cout<<"No\n";
							return ;
						}	
					}
				}
			}
		}
	}
	if(g[n][m]=='#')//出口被堵住了
	{
		if(cnt==0)//没有好人
			cout<<"Yes\n";
		else
			cout<<"No\n";
		return ;
	}
	dfs(n,m);//搜索能走出迷宫的好人数
	if(ans==cnt)
		cout<<"Yes"<<"\n";
	else
		cout<<"No"<<"\n";
}
int main()
{
	int T;
	cin>>T;
	while(T--)
		solve();	
	return 0;
}

AC代码2(BFS):

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
int dir[4][2]={1,0,-1,0,0,1,0,-1};
char g[55][55];
bool vis[55][55];
int n,m;
int cnt=0,ans=0;
bool check(int x,int y)
{
	return (x>0&&y>0&&x<=n&&y<=m);
}
void bfs()
{
	typedef pair<int,int> P;
	queue<P> q;
	vis[n][m]=1;
	q.push(P(n,m));
	while(!q.empty())
	{
		P temp=q.front();
		q.pop();
		int x=temp.first;
		int y=temp.second;
		for(int i=0;i<4;i++)
		{
			int dx=x+dir[i][0];
			int dy=y+dir[i][1];
			if(check(dx,dy)&&g[dx][dy]!='#'&&!vis[dx][dy])
			{
				if(g[dx][dy]=='G')
					ans++;
				q.push(P(dx,dy));
				vis[dx][dy]=1;	
			}
		}	
	}
}
void solve()
{
	ans=0;
	cnt=0;
	memset(vis,0,sizeof(vis));
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			cin>>g[i][j];
			if(g[i][j]=='G')//统计好人个数
				cnt++;
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(g[i][j]=='B')
			{
				for(int k=0;k<4;k++)
				{
					int dx=i+dir[k][0];
					int dy=j+dir[k][1];
					if(check(dx,dy))//四周
					{
						if(g[dx][dy]=='.')//堵墙
							g[dx][dy]='#';
						if(g[dx][dy]=='G')//坏人可以跟着好人走出去
						{
							cout<<"No\n";
							return ;
						}	
					}
				}
			}
		}
	}
	if(g[n][m]=='#')//出口被堵住了
	{
		if(cnt==0)//没有好人
			cout<<"Yes\n";
		else
			cout<<"No\n";
		return ;
	}
	bfs();//搜索能走出迷宫的好人数
	if(ans==cnt)
		cout<<"Yes"<<"\n";
	else
		cout<<"No"<<"\n";
}
int main()
{
	int T;
	cin>>T;
	while(T--)
		solve();	
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值