专栏文章

题解:CF1955G GCD on a grid

CF1955G题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mioxoeuh
此快照首次捕获于
2025/12/03 02:50
3 个月前
此快照最后确认于
2025/12/03 02:50
3 个月前
查看原文

题目大意

对于 n×mn \times m 的网格中,每一个格子都有一个对应的 a[i][j]a[i][j],求出从 a[1][1]a[1][1]a[n][m]a[n][m] 路径中所有数的最大公约数所能达到的最大值。

思路简述

好水的绿题。 观察到数据范围 n,mn,m 较小,且 a[i][j]106a[i][j] \le 10^6
考虑暴力乱搞。
由于所有路径必定经过 a[1][1]a[1][1],所以最后输出的答案必定为 a[1][1]a[1][1] 的因数。
故而我们可以先找出 a[1][1]a[1][1] 的所有因数,从大到小到暴力枚举答案,每个检验一下是否存在合法方案,若存在,则输出。
如何检验呢。
考虑用 f[i][j]f[i][j] 表示第 iijj 列的位置是否可以到达,则转移方程可以表示为:
f[i][j]={0xa[i][j]f[i1][j]f[i][j1],xa[i][j]f[i][j]=\left\{\begin{matrix} 0,x\nmid a[i][j] \\ f[i-1][j] | f[i][j-1],x\mid a[i][j] \end{matrix}\right.
这里存约数时使用优先队列或者开个数组排序一下都可以,个人认为优先队列更方便一些,所以我是使用优先队列实现的。
这里要记得每次检验答案是否成立时要清空 ff 数组和队列,而且 memset 容易超时。
结合代码看看挺好懂的,结束撒花撒花。

代码实现

CF提交记录
马蜂良好。
CPP
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 110;
int a[N][N], f[N][N]; 
priority_queue<int> q;
int n, m; 
bool check (int x) { // 检验 
	for (int i = 1; i <= n; i ++ ) {
		for (int j = 1; j <= m; j ++ ) {
			f[i][j] = 0;
		}
	}
	f[1][1] = 1; // 初始化 
	for (int i = 1; i <= n; i ++ ) {
		for (int j = 1; j <= m; j ++ ) {
			if (i == 1 && j == 1) continue;
			if (a[i][j] % x == 0) {  
				f[i][j] = f[i - 1][j] | f[i][j - 1]; // 从上方和左边转移 
			}
		}
	}
	return f[n][m]; // 返回 
}
void solve () {
	while (!q.empty()) q.pop(); // 清空 
	cin >> n >> m;
	for (int i = 1; i <= n; i ++ ) {
		for (int j = 1; j <= m; j ++ ) {
			cin >> a[i][j];
		}
	}
	for (int i = 1; i <= sqrt(a[1][1]); i ++ ) {
		if (a[1][1] % i == 0) {
			q.push(i); q.push(a[1][1] / i);
		}
	} // 处理因数 
	while (!q.empty()) {
		int x = q.top(); q.pop();
		if (check(x)) { // 检验 
			cout << x << "\n";
			return;
		}
	}
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
    int T; cin >> T;
    while (T --) solve();
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...