链接: link.
题意:
给你一个数n,求最小的数x使得x的平方等于n,运算过程中只以个位作为有效数字,比如正常情况4×4=16,在这里4×4=6;正常情况17×17=289,在这里17×17=149.
思路:
首先写一下乘法竖式。
1、首先可以发现,得到的答案的位数一定是一个奇数,而且是x的位数乘2加1,所以答案位数一定是偶数。那么如果n的位数+1是一个奇数,一定找不到x。
2、再来看能找的情况,我们假设n有p位,那么x就有k = (p+1)/2位,可以发现通过枚举n的最高位(称它为第1位)可以找到符合的a,然后依次向后搜索到n的第k位就可以确定abcd四个数字,也就是x的值,然后再通过余下的几位来验算是否可行。
3、可以发现每一位的值,都是交叉相乘相加后取余,如果第3位,就是1×3,2×2,1×3(这里的1,2,3表示下标)。
注意:
1、因为要找到最小的x,所以从最高位开始搜索,一旦找到直接return。
2、n的位数最多有25位。
代码
#include <bits/stdc++.h>
#define ll long long
#define T int T;scanf("%d", &T);while(T--)
using namespace std;
const int mod = 998244353;
const int maxn = 2e5+10;
string s;
int k; //x的位数
int a[30]; //存x的每一位
int ok = 0; //标记是否找到
vector<int> ans;
void dfs(int x){
if(ok) return;
if(x>=k){
int f = 1;
for(int i = k; i < s.size(); i++){ //验算
int cnt = 0;
int p = i-(k-1);
for(int j = p; j < s.size(); j++){ //交叉相乘相加取余
cnt = (cnt+(a[j])*(a[k-1-(j-p)]))%10;
}
if(cnt != s[i]-'0'){
f = 0;
break;
}
}
if(f){ //如果验算发现没问题
for(int i = 0; i < k; i++){
ans.push_back(a[i]);
ok = 1;
}
}
return;
}
for(int i = 0; i < 10; i++){
if(ok) return;
a[x] = i; //计算当前这位为i时可不可行
int cnt = 0; //值
for(int j = 0; j <= x; j++){ //交叉相乘相加取余
// cout << "-> ";
// cout << a[j] << " " << a[x-j] << endl;
cnt = (cnt+(a[j])*(a[x-j]))%10;
}
// cout << "=== " << x <<" "<<i<< " " << cnt << endl;
if(cnt==s[x]-'0'){ //如果可行,继续搜索下一位
a[x] = i;
// printf("---> a[%d] = %d\n", x, i);
dfs(x+1);
}
}
}
int main(){
cin >> s;
if((s.size()+1)&1){
cout << -1 << endl;
return 0;
}
k = (s.size()+1)/2;
dfs(0);
if(ok) for(auto i : ans) cout << i;
else cout << -1 << endl;
return 0;
}