题目大意
给定一个数,在恰好修改某一位的情况下使修改后的数字成为某个数的平方。问有多少种修改方式。
题目思路
每一位有至多9种修改方式,n的最多只有4位。因此我们只需要在最外层枚举每一位,第二层枚举0-9的数字,共枚举十次,对于首位要进行特判,如果是首位且第二层修改后的数字是0,则不修改;或者n该位原本的数字与第二层修改后的数字一致,也不进行修改。最后当第二层的数字符合修改条件后,进入第三层循环枚举位数,将新数字组装起来,判断他开根号是否为正整数,若为正整数则符合要求,否则不符合。
由于数据量比较大,t 最大为10^6,我们若对于每个n都进行三层循环去找的话,时间复杂度可高达 4*10*4*10^6 = 1.6*10^8 会超时。这个时候我们可以想到用打表的方式去处理,先将1000-9999的这近10000个数字进行处理存入数组。然后每个n直接输出已经存下来了的答案即可,时间复杂度为 4*10*4*10^4 + 1.0*10^6 = 2.6*10^6。
参考代码
#include<bits/stdc++.h>
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
const ll mod = 998244353;
using namespace std;
int b[20000];
int a[10];
void pre() { //打表处理
for (int l = 1000; l <= 9999; l++) {
int ans = 0; //该数字的位数
int n = l;
while (n) {
a[++ans] = n % 10;
n /= 10;
}
int sum = 0;
for (int i = ans; i >= 1; i--) { // 枚举每一位
for (int j = 0; j <= 9; j++) { // 枚举修改后的数字
if ((j == 0 && i == ans) || j == a[i]) {
continue;//若当前为首位且为0或者当前位原来的数字和修改后的数字一致,不符合要求
}
int temp = 0;//新数字
for (int k = ans; k >= 1; k--) {
if (i == k) { //若该位是修改的位置,则拼接的是新数字j
temp = temp * 10 + j;
}
else {
temp = temp * 10 + a[k];
}
}
if (!fmod(sqrt(temp * 1.0), 1)) {//若新数字开根号是整数则方案数加一
sum++;
}
}
}
b[l] = sum;//记录
}
}
int main() {
int t;
cin >> t;
pre();
while (t--) {
int n;
cin >> n;
cout << b[n] << endl;
}
return 0;
}