题意; 给出一个矩阵,询问是否能从乘法表中找出他的位置
思路:
对于每个数字 如果他可以拆解为 x1 *y1 x2*y2那么他必定有可能出现在X1行Y1列, X2行Y2列。那么如果已知了两个数字,那我们就直接可以确定
他在哪个矩阵部分。 那么我们就可以用这个矩阵验证已知的每一项。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3 + 50;
ll prim[10][N], a[N][N];
ll x[10], y[10], tot[10], cnt;
char s[N];
ll get(){
ll num = 0;
if(s[0] == '?') return -1;
for(int i = 0; i < strlen(s); i++) num = num * 10 + s[i] - '0';
return num;
}
void split(ll num){
for(ll i = 1; i * i <= num; i++){
if(num % i == 0) {
prim[cnt][++tot[cnt]] = i;
prim[cnt][++tot[cnt]] = num / i;
}
}
}
int main(){
int T;
scanf("%d", &T);
for(int kase = 1; kase <= T; kase++){
ll n, m;
cnt = 0;
memset(tot, 0, sizeof(tot));
memset(x, 0, sizeof(x));
memset(y, 0, sizeof(y));
memset(a, 0, sizeof(a));
memset(prim, 0, sizeof(prim));
scanf("%lld%lld", &n, &m);
for(ll i = 1; i <= n; i++){
for(ll j = 1; j <= m; j++){
scanf("%s", s);
a[i][j] = get();
if (cnt == 2) continue;
if(a[i][j] != -1) {
cnt++;
x[cnt] = i, y[cnt] = j;
split(a[i][j]);
}
}
}
printf("Case #%d: ", kase);
int ok = 1, tx = 0;
if(cnt == 0) {
puts("Yes");
continue;
}else if(cnt == 1) {
ok = 0;
ll num = a[x[1]][y[1]];
for(ll i = 1; i <= tot[1]; i++) {
// cout << prim[1][i] << " " << num / prim[1][i] << endl;
if(prim[1][i] - x[1] + 1 > 0 && num / prim[1][i] - y[1] + 1 > 0) ok = 1;
// cout << ok << endl;
}
}else {
for(ll i = 1; !tx && i <= tot[1]; i++) {
for(ll j = 1; !tx && j <= tot[2]; j++) {
ll num1 = a[x[1]][y[1]], num2 = a[x[2]][y[2]];
ll x1 = prim[1][i], y1 = num1 / prim[1][i], x2 = prim[2][j], y2 = num2 / prim[2][j];
if(x1 - x2 == x[1] - x[2] && y1 - y2 == y[1] - y[2]) {
tx = i;
}
}
}
ll num = a[x[1]][y[1]];
if(prim[1][tx] - x[1] + 1 < 1 || num / prim[1][tx] - y[1] + 1 < 1) ok = 0;
else {
ll zx = prim[1][tx] - x[1] + 1, zy = num / prim[1][tx] - y[1] + 1;
for(ll i = 1; i <= n; i++){
for(ll j = 1; j <= m; j++){
ll num = (zx + i - 1) * (zy + j - 1);
if(a[i][j] != -1 && a[i][j] != num) ok = 0;
}
}
}
}
if(ok) puts("Yes");
else puts("No");
}
return 0;
}