/*由两个点的值及相对位置求解左上角点的坐标,解的判断很麻烦,wr*/
#include<bits/stdc++.h>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const ll M=1e9,N=1e3+10;
struct point
{
int x,y,v;
}pq[N*N];
int n,m,k;
int jud(ll x,ll y)
{
int x0=pq[0].x,y0=pq[0].y;
for(int i=2;i<k;i++)
{
int dx=pq[i].x-x0,dy=pq[i].y-y0;
if((x+dx)*(x+dy)!=pq[i].v) return 0;
}
return 1;
}
void read()
{
k=0;
char ch;
scanf("%d%d",&n,&m);getchar();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%c",&ch);
if(ch=='?') {getchar();continue;}
int num=ch-'0';
while(ch=getchar())
{
if(!(ch>='0'&&ch<='9')) break;
num=num*10+(ch-'0');
}
pq[k].x=i;pq[k].y=j;pq[k++].v=num;
}
}
int main()
{
int t,ca=1;
scanf("%d",&t);
while(t--)
{
read();
printf("Case #%d: ",ca++);
if(k==0) {printf("Yes\n");continue;}
if(k==1)
{
int flag=0;
for(int i=1;i*i<=pq[0].v;i++)
{
if(pq[0].v%i==0&&pq[0].v/i>=pq[0].y&&i>=pq[0].x) {flag=1;printf("Yes\n");break;}
if(pq[0].v%i==0&&pq[0].v/i>=pq[0].x&&i>=pq[0].y){flag=1;printf("Yes\n");break;}
}
if(flag) continue;
printf("No\n");continue;
}
int n1=pq[1].x-pq[0].x,m1=pq[1].y-pq[0].y;
int c1=pq[0].v,c2=pq[1].v;
ll c=(c2-c1-n1*m1)*(c2-c1-n1*m1)-4*n1*m1*c1;//b^2-4ac
if(c<0) {printf("No\n");continue;}
double temp=sqrt(c);
if(temp-(ll)temp>0.00000001) {printf("No\n");continue;}
ll x1,y1,x2,y2;
if(pq[0].x==pq[1].x)
{
if((c2-c1)>=m&&(c2-c1)%m1==0)
{
x1=(c2-c1)/m1;
if(c2>=x1&&c2%x1==0)
{
y1=c2/x1;
if(jud(x1,y1)){printf("Yes\n");continue;}
}
}
printf("No\n");
continue;
}
if(pq[0].y==pq[1].y)
{
if((c2-c1)>=n1&&(c2-c1)%n1==0)
{
y1=(c2-c1)/n1;
if(c2>=y1&&c2%y1==0)
{
x1=c2/y1;
if(jud(x1,y1)){printf("Yes\n");continue;}
}
}
printf("No\n");
continue;
}
y1=c2-c1-n1*m1+temp;y2=c2-c1-n1*m1-temp;//y1,y2
if(y1>=1&&y1<=M&&y1>=(2*n1)&&y1%(2*n1)==0)
{
y1=y1/(2*n1);
if(c1>=y1&&c1%y1==0)
{
x1=c1/y1;
if(jud(x1,y1)) {printf("Yes\n");continue;}
}
}
if(y2>=1&&y2<=M&&y2>=(2*n1)&&y2%(2*n1)==0)
{
y2=y2/(2*n1);
if(c1>=y2&&c1%y2==0)
{
x2=c2/y2;
if(jud(x2,y2)){printf("Yes\n");continue;}
}
}
printf("No\n");
}
return 0;
}
/*暴力枚举sqrt级ac*/
#include<bits/stdc++.h>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1000;
struct Node
{
int x,y,v;
}a[N*N+100];
int jud(int p)
{
int flag;
for(int i=1;i*i<=a[0].v;i++)
{
if(a[0].v%i==0)
{
if(a[0].v/i>=a[0].x&&i>=a[0].y)
{
flag=0;
for(int k=1;k<p;k++)
{
if((a[k].x-a[0].x+a[0].v/i)*(a[k].y-a[0].y+i)!=a[k].v){flag=1;break;}
}
if(flag==0){return 1;}
}
if(a[0].v/i>=a[0].y&&i>=a[0].x)
{
flag=0;
for(int k=1;k<p;k++)
{
if((a[k].x-a[0].x+i)*(a[k].y-a[0].y+a[0].v/i)!=a[k].v){flag=1;break;}
}
if(flag==0){return 1;}
}
}
}
return 0;
}
int main()
{
char str[100];
int t,kcase=1;
scanf("%d",&t);
while(t--)
{
int n,m,p=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%s",str);
if(strlen(str)==1&&str[0]=='?') continue;
int num=0,len=strlen(str);
for(int k=0;k<len;k++)
num=num*10+str[k]-'0';
a[p].x=i;a[p].y=j;a[p++].v=num;
}
printf("Case #%d: ",kcase++);
if(p==0){printf("Yes\n");}
else if(p==1)
{
int flag=0;
for(int i=1;i*i<=a[0].v;i++)
{
if(a[0].v%i==0)
{
if(a[0].v/i>=a[0].x&&i>=a[0].y){flag=1;break;}
if(a[0].v/i>=a[0].y&&i>=a[0].x){flag=1;break;}
}
}
if(flag) {printf("Yes\n");}
else printf("No\n");
}
else
{
if(jud(p)) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}
点击打开链接