有一个老式计算器,只能显示n位数字。有一天,你无聊了,于是输入一个整数k,然后反复平方,直到溢出。每次溢出,计算器会显示出结果最高n位和一个错误标记。然后清除错误标记,继续平方。如果一直这样一直做下去,能得到的最大数是多少,比如当n=1,k=6时,计算器将依次显示6 , 3 (36的最高位),9,8(81的最高位),6(64的最高位),3…
【输入格式】
输入的第一行为一个整数T(1<=T<=200),即测量数据的数量,一下T行,每行保包含两个整数n和k(1<=n<=9,0<=k<=10n)。
【输出格式】
对于每组数据,输出你能得到的最大数。
#include<iostream>
#include<sstream>
#include<set>
using namespace std;
typedef long long LL;
int next(int n,int k)
{
stringstream ss;
ss<<(LL)k*k;
string s=ss.str();
if(s.length()>n)
s=s.substr(0,n);
stringstream ss1;
int ans;
ss1>>ans;
return ans;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
int k;
scanf("%d%d",&n,&k);
ans=k;
set<int >s;
while(s.count())
{
s.insert(k);
if(k>ans) ans=k;
k=next(n,k);
}
cout<<ans<<endl;
}
return 0;
}
上述程序的运行时间为4.5秒,STL的string很慢,而stringstream更慢,所以需要把他们换掉。
#include<iostream>
using namespace std;
typedef long long LL;
int buf[10];
int next(int n,int k)
{
if(!k) retue 0;
int L=0;
LL k2=(LL) k*k;
while(k2)
{
buf[L++]=k%10;//分离并保存K^2^的各个数字
K2/=10;
}
if(n>L)n=L;//不能让取得的位数超过数字背身已有的位数
int ans=0;
for(int i=0;i<n;i++)
ans=ans*10+buf[--L];//把前面的n位重新的组合起来
return ans;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,k;
cin>>n>>k;
int ans=k;
int k1=k;
int k2=k;
do{
k1=next(n,k1);//小孩1
k2=next(n,k2); if(k2>ans) ans=k2;//小孩二,第一步
k2=next(n,k2); if(k2>ans) ans=k2;//小孩二,第一步
}while(k1!=k2);//追上以后才停止
cout<<ans<<endl;
}
}
代码分析:
主函数中的K1,k2用到了Floyd判圈算法,想象一下,假设有两个孩子在一个"可以无限向前跑"的赛道上赛跑,同时出发,但其中,
一个孩子的数独是另一个孩子速度的两倍。如果跑到是直的那么跑得快的小孩将一直在前面,但是如果跑有环,则跑的快的小孩将"追上"跑的慢的小孩。正如我们在主函数中写的k1走了一步,k2走了两步。又因为取得整数是有环型分布趋势的所以k2会追上k1的。