【SSLOJ1460】逛机房

题目

思路

考虑到可以特判 \(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;
}
posted @ 2020-08-11 13:39  stoorz  阅读(106)  评论(0编辑  收藏  举报