题目
思路
考虑到可以特判 \(n=10^6\),这样每个数就只有 6 位。可以考虑 bfs。
但是每次询问都 bfs 一次复杂度显然不对。发现目标状态是一样的,且 \(10^6\) 以内的完全平方数只有 \(10^3\) 个,所以可以从目标状态开始搜索,然后 \(O(1)\) 询问。
那么每次有两种转移方式:
- 将这个数字任意一位修改成任意一个数(注意不可以将最高位修改为 0)。
- 将一个位置前的数字全部向前移一位,然后在这个空出来的位置修改成任意数字。
时间复杂度 \(O(n+Q)\)。
代码
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include <bits/stdc++.h>
using namespace std;
const int N=1000010;
int Q,n,dis[N];
bool vis[N];
struct node
{
int a[7];
};
queue<node> q;
int get(node x)
{
int s=0;
for (int i=1;i<=6;i++)
s=s*10+x.a[i];
return s;
}
void bfs()
{
while (q.size())
{
node u=q.front();
q.pop();
int len=1;
while (len<6 && !u.a[len]) len++;
for (int i=1;i<=6;i++)
for (int j=0;j<=9;j++)
{
if (i==len && !j) continue;
node v=u; v.a[i]=j;
if (!dis[get(v)])
{
dis[get(v)]=dis[get(u)]+1;
q.push(v);
}
}
if (len==1) continue;
for (int i=len;i<=6;i++)
{
node v=u;
for (int j=1;j<i;j++)
v.a[j]=v.a[j+1];
for (int j=0;j<=9;j++)
{
v.a[i]=j;
if (!dis[get(v)])
{
dis[get(v)]=dis[get(u)]+1;
q.push(v);
}
}
}
}
}
int main()
{
for (int i=1;i<1000;i++)
{
int p=i*i;
node a;
for (int j=6;j>=1;j--)
a.a[j]=p%10,p/=10;
q.push(a);
dis[get(a)]=1;
}
bfs();
scanf("%d",&Q);
while (Q--)
{
scanf("%d",&n);
if (n==1000000) printf("0\n");
else printf("%d\n",dis[n]-1);
}
return 0;
}