Codeforces Round #648 (Div. 2)

本博客不包含最后一题

A.Matrix Game

大意: 给你一个 n × m n×m n×m 的 01矩阵,两个玩家一先一后把 0 的 a i j a_{ij} aij 变为 1,条件为第 i i i 行和第 j j j 列没有 1,当一名玩家无点可改,游戏结束
思路: 我们每改一个点,就会有 1 行和 1 列失效,那么,在这个 n × m n×m n×m 的 01矩阵 中,最多可以变 m i n ( n , m ) min(n, m) min(n,m) 个点,我们算出还有几个点可改,再判奇偶性即可
AC代码:

#include 
using namespace std;
int tmp,n,m,a;
int l[55], r[55];
void solve()
{
	memset(l, 0, sizeof(l));
	memset(r, 0, sizeof(l));
	cin >> n >> m;
	int L = n, R = m;//记录还有几行几列是没有 1 的
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
		{
			cin >> a;
			if (a == 1)
			{
				if (l[i] == 0)L--;
				if (r[j] == 0)R--;
				l[i] = r[j] = 1;
			}
		}
	if (min(L, R) % 2 == 1)cout << "Ashish\n";
	else cout << "Vivek\n";
}
int main()
{
	cin>>tmp;
	while(tmp--)
		solve();
	return 0;
}

B.Trouble Sort

大意: 给你一个包含 n n n 个数的数组 a,和一 一对应的 type 数组 b(只含 0 和 1)你可以交换两个数 a i a_{i} ai a j a_{j} aj,当且仅当 b i b_{i} bi 不等于 b j b_{j} bj,问是否经过任意次交换,使得数组 a 是非递减的
思路: 首先我们知道,如果 type 全为 0 或 1,这个数组是操作不了的,这时候判断他最初是不是非递减的,如果不是,就是NO;当 type 数组中有至少 1 个不同时,那它就是可以任意调换的
AC代码:

#include 
using namespace std;
int tmp,n,m,x,y;
int a[550], b[550];
void solve()
{
	int z = 0, o = 0;
	cin >> n;
	for (int i = 1; i <= n; i++)cin >> a[i];
	for (int i = 1; i <= n; i++)
	{
		cin >> b[i];
		if (b[i] == 1)o = 1;
		if (b[i] == 0)z = 1;
	}
	bool f = 0;
	for (int i = 1; i < n; i++)
		if (a[i] > a[i + 1])f = 1;
	if (f && (z + o != 2))cout << "NO\n";//当 type 只有 0 或只有 1,且原数组不是非递减的,输出 NO
	else cout << "YES\n";
}
int main()
{
	cin>>tmp;
	while(tmp--)
		solve();
	return 0;
}

C.Rotation Matching

大意: 给你包含 n n n 个数的 a a a b b b 数组,他们都是 [ 1 , n ] [1,n] [1,n] 的任意一个排列,你可以左移或右移任意数组任意次,问在所有情况中, a a a b b b 数组能对上的位置最多有多少个。当 i = = j i==j i==j a i = = b i a_{i}==b_{i} ai==bi,我们说这个位置能对上。左移一个数组表示在下方,右移相反。
思路: 我们确定数组 a a a b b b 每相同的数字对齐要移动多少格(定为第二个数组右移格数),相同的移动格数,最多的则为最终答案
AC代码:

#include 
using namespace std;
int tmp,n,m;
int a[200005], b[200005];
int posa[200005], posb[200005];//记录每个数字的位置
int num[200005];
void solve()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		posa[a[i]] = i;
	}
	for (int i = 1; i <= n; i++)
	{
		cin >> b[i];
		posb[b[i]] = i;
	}
	for (int i = 1; i <= n; i++)
	{
		int dif = posa[i] - posb[i];
		if (dif < 0)dif += n;//小于 0 表示这里要左移,下标 +n,把它变为右移
		num[dif]++;
	}
	//num[0]表示不移动时能对上的数字个数,移动 n 次就是没有移动,可以不用加入比较
	cout << *max_element(num, num + n) << endl;//找到 num 数组 [0,n) 中最大的数
}
int main()
{
	solve();
	return 0;
}

D.Solve The Maze

大意: 给你 n × m n×m n×m 的迷宫,包含如下几种 Cell
Empty — ‘.’
Wall — ‘#’
Good person — ‘G’
Bad person — ‘B’
保证出口的 Cell ( n , m ) (n, m) (n,m) 为Empty
我们可以在任意 Empty 的 Cell 上建立一个 Wall,使得这个 Cell 无法到达,B 和 G 只能上下左右移动,且不能移动到 Wall 的 Cell,但可以移动到 B 或 G 的 Cell,问我们能不能通过建墙,使得所有 B 不能到达出口,且所有 G 都能到达出口(允许没有 G)
思路: 先把 B 困住是比较容易的,只要把 B 的 4 个方向都建墙就行,建好后再从出口 bfs 一遍,把能走到的 Cell 标记一下,看看有没有哪个 G 的位置是没有被标记到的
AC代码:

#include 
using namespace std;
#define pii pair 
#define pb push_back
#define clr(a, b) memset((a), (b), sizeof(a))
int tmp,n,m,x,y;
char mp[55][55];
vector<pii>G, B;//存放 B、G的坐标
bool vis[55][55];//标记 bfs过后能走到的位置
int dir[4][2] = { {1, 0},{-1, 0},{0,1},{0,-1} };//bfs四个方向
void bfs(int x, int y)//最简单的 bfs模板
{
	queue<pii>q;
	q.push(pii(x, y));
	vis[x][y] = 1;
	while (q.size())
	{
		pii tmp = q.front();
		q.pop();
		for (int i = 0; i < 4; i++)
		{
			int nx = tmp.first + dir[i][0];
			int ny = tmp.second + dir[i][1];
			if (nx > 0 && nx <= n && ny>0 && ny <= m && !vis[nx][ny] && mp[nx][ny] != '#')
			{
				vis[nx][ny] = 1;
				q.push(pii(nx, ny));
			}
		}
	}
}
void solve()
{
	G.clear();
	B.clear();
	clr(mp, ' ');
	clr(vis, 0);
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
		{
			cin >> mp[i][j];
			if (mp[i][j] == 'B')B.pb(pii(i, j));
			else if (mp[i][j] == 'G')G.pb(pii(i, j));
		}
	bool f = 0;
	for (pii p : B)//遍历 B容器 
	{
		int i = p.first, j = p.second;
		//如果 B旁边就是 G,那么只要存在 G,且 G能到出口,B也能,所有答案一定是 NO
		if (mp[i - 1][j] == 'G' || mp[i + 1][j] == 'G' || mp[i][j + 1] == 'G' || mp[i][j - 1] == 'G')
		{
			f = 1;
			break;
		}
		if (mp[i - 1][j] == '.')mp[i - 1][j] = '#';
		if (mp[i + 1][j] == '.')mp[i + 1][j] = '#';
		if (mp[i][j + 1] == '.')mp[i][j + 1] = '#';
		if (mp[i][j - 1] == '.')mp[i][j - 1] = '#';
	}
	//我们在给 B建墙的时候,可能会在出口处也建了墙,那么如果迷宫里面有 G,是肯定出不来的
	if (f || (G.size() > 0 && mp[n][m] == '#'))
	{
		cout << "NO\n";
		return;
	}
	if (mp[n][m] != '#')bfs(n, m);//如果出口没有被堵住,就 bfs
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
		{
		//B在被标记过的位置,表示可以逃出去
			if (vis[i][j] && mp[i][j] == 'B')
			{
				cout << "NO\n";
				return;
			}
		}
	for (pii p : G)
	{
	//只要有一个 G不在被标记的位置,答案为 NO
		if (vis[p.first][p.second] != 1)
		{
			cout << "NO\n";
			return;
		}
	}
	cout << "YES\n";
}

int main()
{
	cin>>tmp;
	while(tmp--)
		solve();
	return 0;
}

E.Maximum Subsequence Value

大意: 给你 n n n 个数,要你选出 k k k 个数,先把他们转为 2 进制,对于二进制的第 i i i 位,如果你选的 k k k 个数里至少有 m a x ( 1 , k − 2 ) max(1,k−2) max(1,k2) 个数字的二进制的第 i i i 位是 1,答案就 += 2 i 2^i 2i,求怎么取 k k k 个数能让最后答案最大,比如 3,4,1,二进制为011,100, 001。三个数字全选,二进制里三个位置为 1 的数量都有 1 个,因此答案为 20 + + + 21 + + + 22 = = = 7
思路: 贪心算法,当 k = 0 、 1 、 2 、 3 k=0、1、2、3 k=0123 时结果都是 1,但当 k = 4 k=4 k=4 时,选出的二进制必须有 2 个数的第 i i i 位位置为 1 才能 += 2 i 2^i 2i,所以最好选择 3 个数字( k = 3 k=3 k=3),而且是最优的 3 个数字,因此对所有的数暴力列举( n 3 n^3 n3)即可
AC代码:

#include 
using namespace std;
#define ll long long
int n; 
ll a[505];
ll ans = 0;
void solve()
{
	cin >> n;
	for (int i = 0; i < n; i++)
		cin >> a[i];
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < n; ++j) {
			for (int k = 0; k < n; ++k) {
			// |这个竖杠表示当两个都为 0时,结果才为 0
				ans = max(ans, a[i] | a[j] | a[k]);
			}
		}
	}
	cout << ans << endl;
}
int main()
{
	solve();
	return 0;
}

F. Swaps Again

大意: 给你一个数组 a,每次只能选取一个数 K K K 交换前缀的 K K K 个数和后缀的 K K K 个数,问是否能变成数组 b
思路: 举个例子, 12345 1 2 3 4 5 12345,可以变成 52341 5 2 3 4 1 52341 41352 4 1 3 5 2 41352 21354 2 1 3 5 4 21354,多试几个样例发现对称的数经过交换后的位置依然是相对对称的,像这个例子中 1 和 5,2 和 4 的位置都是对称的,因此我们可以直接遍历 b 数组,如果 b 数组中存在对称的位置和 a 数组对称的位置的数字相同,那么直接标记表示该位置已经插入过,最后要特判一下 n 为奇数时最中间那个位置的数字是否相同
AC代码:

#include
using namespace std;
#define clr(a, b) memset((a), (b), sizeof(a))
typedef long long ll;
int a[1000],b[1000],vis[1000];
int main()
{
	int t,n;
	cin>>t;
	while(t--){
		cin>>n;
		clr(vis,0); 
		for(int i=1;i<=n;i++) cin>>a[i];
		for(int i=1;i<=n;i++) cin>>b[i];
		int l=1,r=n;bool flag=true;
		while(l<r){
			int f=0;
			for(int i=1;i<=n;i++){ // a 数组第 i 个一个个和 b 数组对比,直到找到相同的数值
				if(a[l]==b[i]&&a[r]==b[n-i+1]&&!vis[i]&&!vis[n-i+1]){
					vis[i]=1,vis[n-i+1]=1,f=1;break;
				}
			}
			if(!f){
				flag=false;break;
			}
			l++,r--;
		}
		if(n&1&&a[n/2+1]!=b[n/2+1]) flag=false;
		if(flag) cout<<"Yes"<<endl;
		else cout<<"No"<<endl; 
	}
	return 0;	
}

你可能感兴趣的:(比赛集)