Codeforces Round #766 (Div. 2)

A.Not Shading

题意

给你一个m*n的棋盘,每个位置分别放置白棋和黑棋。如果行(列)中有一个黑色棋子可以进行一次操作使得整行(列)中的所有棋子都变成成黑色,问欲使(r,c)位置要变成黑色棋子要进行几次操作?

题解

由于可以进行整行、整列变换,只要棋盘上有一个黑色棋子,那么每个位置都可以变成黑色棋子,所以只有三种情况
1.(r,c)位置上已经是黑色棋子就不用进行操作
2.r行上有一个黑色棋子,或c列上有一个黑色棋子,那么只需要一次操作即可
3.如果r行上和c列上都没有黑色棋子,但是棋盘其他位置有一个黑色棋子,那么进行两次操作即可使得(r,c)位置变成黑色

代码

#include <iostream>
using namespace std;
const int maxn = 55;
char arr[maxn][maxn];
int main(){
	//freopen("in.txt","r",stdin);
	int t; cin >> t;
	for(int T = 1; T <= t; T++){
		int n, m, r, c; cin >> n >> m >> r >> c;
		bool isblack = false;
		for(int i = 1; i <= n; i++){
			for(int j = 1; j <= m; j++){
				cin >> arr[i][j];
				if (arr[i][j] == 'B') isblack = true;
			}
		}
		if (arr[r][c] == 'B'){
			printf("0\n");
			continue;
		}

		bool ans = false;
		for(int i = 1; i <= m; i++){
			if (arr[r][i] == 'B') {
				ans = true;
				break;
			}
		}
		for(int i = 1; i <= n; i++){
			if (arr[i][c] == 'B') {
				ans = true;
				break;
			}
		}
		if (ans){
			printf("1\n");
		}
		else if (isblack){
			printf("2\n");
		}
		else printf("-1\n");

	}
}

B. Not Sitting

题意

有一个n*m的座位,T可以进行涂粉色,涂粉色的座位R不坐。T先涂,然后R选座位,要使得无论T怎么选距离都是最近最后T选座位,要尽量原理R,k为 0 0 0 ~ n ∗ m − 1 n*m-1 nm1 时T和R之间的距离

题解

R选择的位置要在中间,这样能确保无论T选择哪里都不会太远而尽量近。那么显然T选择的位置是四个角落的位置其中一个,然后计算每个位置到四个顶点的最大值,进行储存,因为最后选位置的T所以存四点的最大值。

最后对所有最大值进行排序,即为答案,这是由于T的每种k的涂鸦方案所导致的最佳情况,所以为答案。

代码

#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
typedef long long ll;
//const int maxn = 
int main(){
	//freopen("in.txt","r",stdin);
	int t;
	cin >> t;
	for(int _ = 1; _ <= t; _++){
		int n, m; cin >> n >> m;
		std::vector<int> v;
		for(int i = 1; i <= n; i++){
			for(int j = 1; j <= m; j++){
				int t1 = abs(i - 1) + abs(j - 1);
				int t2 = abs(i - 1) + abs(j - m);
				int t3 = abs(i - n) + abs(j - 1);
				int t4 = abs(i - n) + abs(j - m);
				int maxx = max(max(t1, t2), max(t3, t4));
				v.push_back(maxx);
			}
		}
		sort(v.begin(), v.end());
		for(auto i: v){
			cout << i << " ";
		}
		cout << '\n';
	}

}

C. Not Assigning

题意

题目定义了素数树的概念,

A prime tree is a tree where the weight of every path consisting of one or two edges is prime

定义就帮我们排除了树的度超过2的情况了

及树上任意路径的权重之和都是素数即为素数树,要你求解素数树的权重序列。

题解

参考官方题解所写

1.考虑什么时侯不存在最素数树
即任意顶点的度超过2的时候,素数树是必然不存在的

2.路径怎么样能构成素数?
就需要利用特殊的素数2,因为 3+5=8 奇数+奇数=偶数,偶数必然不会是素数
而2+3=5 即为素数,可以利用这一点交替使用2和3构成全部为素数的路径,从而建立素数树

3.注意素数树是由素数边组成、由素数路径组成即可,并不是要求整条路径之和是素数,参考题目样例

代码

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 1e5+50;
std::vector<pair<int, int>> E[maxn];
bool vis[maxn];

int ans[maxn];//记录每条边的长度
int d[maxn];//统计每个点的度数

int vnum = true;//判断度数不符合的情况


void dfs(int root, int weight){
	if (vis[root]) return;
	vis[root] = true;
	for(pair<int, int> i: E[root]){
		ans[i.second] = weight + 2;
		dfs(i.first, weight^1);
	}
}

int main(){
	int T; cin >> T;
	while(T--){
		//初始化
		
		vnum = true;

		int n; cin >> n;
		for(int i = 0; i <= n; i++){ E[i].clear(); vis[i] = false; d[i] = 0; ans[i] = 0;}
		for(int i = 1; i <= n - 1; i++){
			int u, v; cin >> u >> v;
			E[u].push_back(make_pair(v, i));
			E[v].push_back(make_pair(u, i));
			d[u]++;
			d[v]++;
			if (d[u] > 2 || d[v] > 2) vnum = false;
		}

		if(!vnum) {
			printf("-1\n");
			continue;
		}
		int pos = -1;
		for(int i = 1; i <= n; i++){
			if (d[i] == 1) {
				pos = i;
				break;
			}
		}
		dfs(pos, 0);
		for(int i = 1; i < n; i++) printf("%d ", ans[i]);
		cout << '\n';
	}
}

D. Not Adding

题目

给你n个不同的数字,一次操作为每两个数字求解GCD如果所得的GCD没有出现在序列中,则加入到序列的末尾,问最多能够操作多少次

题解

n的范围是 1 0 6 10^6 106,那么我们可以考虑枚举这 1 1 1~ 1 0 6 10^6 106这些数字,判断是否有可能出现在序列中。

  • 什么情况下会有可能出现x呢?

即,存在 Y 1 Y1 Y1 Y 2 Y2 Y2,……, Y m Y_m Ym ( m > 2 ) (m>2) (m>2) x x x 的倍数

Y i x = t \frac{Y_i}{x}=t xYi=t

因为所有的 Y i Y_i Yi是唯一的,他们又都是x的倍数,所以他们相除所得的公因数只有1

G C D ( Y 1 x , Y 2 x , … … , Y m x ) = 1 GCD(\frac{Y_1}{x},\frac{Y_2}{x},……,\frac{Y_m}{x}) = 1 GCD(xY1xY2xYm)=1
上式存在即可说明 x x x存在.
判断完 x x x出现,并不需要将 x x x加入到队列中(就是不需要多加 t [ x ] = 1 t[x]=1 t[x]=1这一步操作,这是因为x是因子数)

代码

#include <iostream>
#include <set>
#include <algorithm>

using namespace std;
const int maxn = 1e6 + 10;
int t[maxn];
//int arr[maxn];
int gcd(int a, int b){
	if (b == 0) return a;
	else {
		return gcd(b, a % b);
	}
}
int main(){
	//freopen("in.txt","r",stdin);
	fill(t, t + maxn, 0);
	int n; cin >> n;
	for(int i = 0; i < n; i++){
		int x; cin >> x;
		t[x] = 1;
	}
	int ans = 0;
	for(int i = 1; i < 1e6 + 1; i++){
		//if (t[i]) continue;
		int temp = 0;
		for(int j = i; j < 1e6 + 1; j += i){
			if (t[j]) 
				temp = gcd(temp, j / i);
		}
		if (temp == 1 && !t[i]) {
			ans++;
		}
	}
	cout << ans << '\n';
}

E. Not Escaping

题意

简述:要求从建筑物底部 ( 1 , 1 ) (1,1) 11到顶楼 ( n , m ) (n, m) n,m逃脱。

该建筑由 n n n层组成,每层有 m m m个房间。令 ( i , j ) (i,j) (i,j)表示第 i i i层的第 j j j个房间。此外,还安装了 k k k个梯子。第 i i i个梯子允许从 ( a i , b i ) (ai,bi) (ai,bi) 移动到 ( c i , d i ) (ci,di) (ci,di)。如果他使用第 i 个 梯 子 , 可 以 获 得 健 康 点 数 i个梯子,可以获得健康点数 ihi 。 保 证 所 有 梯 子 的 。保证所有梯子的 ai<ci$。
如果在第 i i i 层,可以向左或向右移动。然而,跨楼层旅行是危险的。如果 Ram 从 ( i , j ) (i,j) (i,j) 移动到 ( i , k ) (i,k) (i,k),他会失去 ∣ j − k ∣ ⋅ x i |j−k|⋅x_i jkxi 健康点。
Ram 在 ( 1 , 1 ) (1,1) (1,1) 处进入大楼,而他的直升机在 ( n , m ) (n,m) (n,m) 处等待。如果选择最优路径,他损失的最小生命值是多少?
如果无论走哪条路,他都无法逃脱魔掌,则输出“NO ESCAPE”。

题解

每个梯子的开始点即为该行的关键点,每行的关键点不唯一。
每行的移动方向都是向右边移动,那么每行从(i)移动的花费为
f [ k ] = f [ j ] − ∣ j − k ∣ ⋅ x i f[k] = f[j]-|j−k|⋅x_i f[k]=f[j]jkxi
楼层间的旅行是不允许,只能使用梯子。
然后在根据梯子去更新对应的的 f [ ] f[ ] f[]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值