nssl 1460.逛机房

D e s c r i p t i o n Description Description

给定 T T T组数据,每组数据给定一个数 n n n,对于一个数 x x x,你可以对其进行两种操作

  1. 删除某一位
  2. 更改某一位为任意个位数

求出把其变为完全平方数的最小步数

数据范围: n ≤ 1 0 6 , T ≤ 1 0 3 n\leq 10^6,T\leq 10^3 n106,T103


S o l u t i o n Solution Solution

首先我们把这两种操作做个变形,改成对于一个数 x x x的每一位,可以进行三种操作

  1. 什么都不干
  2. 删掉它
  3. 把它变成任意一个数字

这样一来,我们就可以用 3 6 3^6 36以内的数表示所有的操作,然后简单预处理一手完全平方数,放入对应的位数中比较即可

时间复杂度: O ( 3 l o g 10 k T ) O(3^{log_{10}k}T) O(3log10kT)


C o d e Code Code

#include
#include
#include
#include
using namespace std;int n,T,pw[8],len,ans,lenb,b[8],a[8],c[8],lenc;
vector<int>g[8];
inline long long read()
{
	long long d=1,f=0;char c;
	while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
inline int Get(int x)
{
	int ans=0;
	while(x) ans++,x/=10;
	return ans;
}
inline int Get2(int x)
{
	int ans=0;
	while(x) {if(x%3) ans++;x/=3;}
	return ans;
}
inline bool Comp(int a[],int b[],int len)
{
	for(register int i=1;i<=len;i++) if(a[i]!=b[i]&&a[i]!=999) return false;
	return true;
}
signed main()
{
	for(register int i=1;i<=1000;i++) g[Get(i*i)].push_back(i*i);
	pw[0]=1;
	for(register int i=1;i<=7;i++) pw[i]=pw[i-1]*3;
	T=read();
	while(T--)
	{
		n=read();len=0;
		while(n)
		{
			a[++len]=n%10;
			n/=10;
		}
		ans=len;
		for(register int i=0;i<pw[len];i++)
		{
			if(Get2(i)>ans) continue;
			lenb=0;
			for(register int j=len;j>0;j--)
			{
				if(i/pw[j-1]%3==0)
				{
					if(lenb+a[j]==0) continue;
					b[++lenb]=a[j];
				}
				if(i/pw[j-1]%3==1) continue;
				if(i/pw[j-1]%3==2) b[++lenb]=999;
			}
			for(register int j=0;j<g[lenb].size();j++)
			{
				int x=g[lenb][j];lenc=0;
				while(x)
				{
					c[++lenc]=x%10;
					x/=10;
				}
				reverse(c+1,c+1+lenc);
				if(Comp(b,c,lenb)) {ans=Get2(i);break;}
			}
		}
		printf("%d\n",ans);
	}
}

你可能感兴趣的:(暴力)