Codeforces 766 Div.2题解

Codeforces 766 Div.2题解

A

题意:给你一个矩阵,每一次操作你可以选择一个字符为B的位置(x , y),可以使得x行字符都变为B,或者是让y行字符都变成B

现在问你什么情况下可以使 (x1,y1) 所在的位置字符为B 

简单分析一下:

①当(x1,y1)就是B的时候操作次数是0次

②当矩阵中不存在B的时候,不存在答案,为-1

③当x1行或者y1列存在B,那么操作次数是1次

④否则,就需要两次,从非x1行,非y1列的地方随便操作一个B,可以使得x1行 or y1列中出现一个B,那么就变成了③的情况,答案是2

查看代码

#include<iostream>
#include <vector>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 55;
char a[MAXN][MAXN];
/*
4 10 1
0 3 4 8
5 8 3 6

*/
void solve()
{
	int n,m,x,y;
	scanf("%d %d %d %d",&n,&m,&x,&y);
	int f = 0;
	for(int i = 1;i <= n;++i)	scanf("%s",a[i] + 1);
	for(int i = 1;i <= n;++i)
	for(int j = 1;j <= m;++j)
	{
		if(a[i][j] == 'B')	{
			f = 1;
			break;
		}
	}
	if(!f)	{
		puts("-1");
		return ;
	}
	if(a[x][y] == 'B')
	{
		puts("0");
		return ;
	}
	for(int i = 1;i <= n;++i)
	if(a[i][y] == 'B')	{
		puts("1");
		return ;
	}
	for(int i = 1;i <= m;++i)
	{
		if(a[x][i] == 'B')	{
			puts("1");
			return ;
		}
	}
	puts("2");
}
int main()
{
	int t = 1;
	scanf("%d",&t);
	while(t--)
	solve();
	return 0; 
}

B

题意:

给你一个N * M的矩阵,Tina可以选择其中的k个位置(k∈[0,n * m - 1]),使得这k个位置染色成为粉色,Rahul不会坐在粉色的位置,而Tina可以坐在任何的位置上。然后Rahul和Tina轮流选择位置,Rahul想要最后同Tina坐的尽可能近,而Tina想要和他坐的尽可能远,问你若他们两个都非常聪明,k∈[0 , n * m - 1]这时候的最远距离分别是多少

分析:

①由于k是在 0 ~ n * m - 1范围之内的,那么Rahul会将所有的位置都坐一遍

②由于Tina要坐的和Rahul尽可能的远,那么最优的情况就是选择矩阵的四个角落(很简单的贪心吧)

③K越大,Tina和Rahul的距离会尽可能的远,也就是说答案是递增的

那么我们就可以将所有的位置都遍历一遍,然后和四个角的哈密顿距离进行对比,取最大的那个,最后将数组排序,输出前n * m个数字即可

查看代码

#include<iostream>
#include <vector>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 55;
char a[MAXN][MAXN];
/*
4 10 1
0 3 4 8
5 8 3 6

*/
vector<int> ans;
int dis(int x,int y,int x1,int y1)
{return abs(x - x1) + abs(y - y1);}
void solve()
{
	ans.clear();
	int n,m;
	scanf("%d %d",&n,&m);
	for(int i = 1;i <= n;++i)
	for(int j = 1;j <= m;++j)
	{
		ans.push_back(max(max(dis(i,j,1,1),dis(i,j,n,m)),max(dis(i,j,1,m),dis(i,j,n,1))));
	}
	sort(ans.begin(),ans.end());
	int siz = n * m - 1;
	for(int i = 0;i <= siz;++i)
	printf("%d%c",ans[i], " \n"[i == siz]);
}
int main()
{
	int t = 1;
	scanf("%d",&t);
	while(t--)
	solve();
	return 0; 
}

C

题意:

给你一棵树,你要给所有的边添加一个权值,使得每一个长度 <= 2的路径权值和都是一个质数

分析:

我们可以直接看到第三个样例,它为什么不能够构成一个Prime树。

①分析可知,两个非2的素数进行相加操作,得到的数字一定不是质数

②如果一个节点的度为3,那么势必需要存在两个2,才可以使得其中的两条边和为质数,但是那两条2的边形成的不是质数,因此存在节点度数 >= 3的树就直接输出-1

③可以知道这颗树是一个链,我们只需要从度数为0的点开始,依次对各条边进行赋值即可(2,5,2,5,2,5,2....依次)

代码有点乱,可以看看正解的代码

查看代码

#include<iostream>
#include <vector>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 7;
bool prime[MAXN * 16 + 1];
int p[MAXN],top = 0;
/*
4 10 1
0 3 4 8
5 8 3 6
*/
vector<int> ans,tmp;
void ini()
{
	top = 0;
	int MAX = 1e6;
	for(int i = 2;i < MAX;++i)
	{
		if(!prime[i])	p[++top] = i;
		for(int j = 1;j <= top && 1ll * p[j] * i < MAX;++j)
		{
			prime[p[j] * i] = 1;
			if(i % p[j] == 0)	break;
		}
	}
}
struct node{
	int x,id;
	node(int x = 0,int id = 0):x(x),id(id){}
};
int deg[MAXN],a[MAXN];
vector<node> g[MAXN];
/*
1
6
3 4
4 5
5 6
2 1
2 3
*/
struct no{
	int x,y,id;
}all[MAXN];
void dfs(int x,int fa,int ls)
{
	for(int i = 0;i < g[x].size();++i)
	{
		node t = g[x][i];
		if(t.x == fa)	continue;
		if(ls == 2)
		a[t.id] = 5;
		else
		a[t.id] = 2;
		dfs(t.x,x,a[t.id]);
	}
}
void solve()
{
	int n;
	scanf("%d",&n);
	for(int i = 1;i <= n;++i)	deg[i] = 0,g[i].clear();
	int f = 0;
	for(int i = 1;i < n;++i)
	{
		int x,y;
		scanf("%d %d",&x,&y);
		deg[x] += 1;
		deg[y] += 1;
		g[x].push_back(node(y,i)),g[y].push_back(node(x,i));
		all[i].id = i;
		all[i].x = x,all[i].y = y;
		if(deg[x] >= 3 || deg[y] >= 3)	f = 1;
	}
	if(f)
	{
		puts("-1");
		return ;
	}
	for(int i = 1;i <= n;++i)
	{
		if(deg[i] == 1)
		{
			for(int j = 1;j < n;++j)
			{
				if(all[j].x == i || all[j].y == i)
				{
					a[all[j].id] = 2;
					dfs(i,0,2);
					for(int j = 1;j < n;++j)
					printf("%d%c",a[j]," \n"[j == n - 1]);
					return ;
				}
			}	
		}
	}
	puts("-1");
}
int main()
{
//	ini();
	int t = 1;
	scanf("%d",&t);
	while(t--)
	solve();
	return 0; 
}

D

题意:

n个数,每一次操作你可以选择其中的两个数进行GCD,然后将得到的数字加入到序列的末尾,当然这个数字不能出现在原序列当中,问你最多操作几次。

分析:

①看到a的最值是1e6我们可以发现这里面一定有猫腻,那么我们可以每次对数字i进行判定,看看它能不能加入到我们的序列当中

②如果一个数能够加入进来,那么所有在序列中的数字能被这个数取余为0的,进行GCD操作一定会得到这个数,具体来说就是:

最终的答案就是ans - n

查看代码

#include <iostream>
#include <vector>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 1e6 + 7;
bool vis[MAXN];
bool prime[MAXN];
int p[MAXN],top = 0;
void ini()
{
	for(int i = 2;i < MAXN;++i)
	{
		if(!prime[i])	p[++top] = i;
		for(int j = 1;j <= top && 1ll * p[j] * i < MAXN;++j)
		{
			prime[p[j] * i] = 1;
			if(i % p[j] == 0)	break;
		}
	}
}
/*
2
4 16
*/
int gcd[MAXN];
void solve()
{
	int n;
	scanf("%d",&n);
	for(int i = 1;i <= n;++i)	{
		int x;
		scanf("%d",&x);
		vis[x] = 1;
	}
	int ans = 0;
	for(int i = 1;i <= 1e6;++i)
	{
		for(int j = i;j <= 1e6;j += i)
		if(vis[j])	gcd[i] = __gcd(gcd[i],j);
		ans += gcd[i] == i;
	}
	printf("%d\n",ans - n);
}
int main()
{
//	ini();
	int t = 1;
//	scanf("%d",&t);
	while(t--)
	solve();
	return 0; 
}
posted @ 2022-01-16 11:34  K0njac  阅读(55)  评论(0编辑  收藏  举报