题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4937
题目大意:给你T组数据,每组数据输入一个小于=1e12的数num,如果这个数的n进制下都是由3,4,5,6这四个数字组成的,则说明这个n进制是num的幸运进制,现在求一个num有几个幸运进制,如果有无限多个幸运进制则输出-1.
题解:
如果输入的num转化后是一位数,显然可以得到3,4,5,6这四个数字应该输出-1。
如果输入的num转化后是二位数,以base作为进制的话,转换问base进制就是num=a*base+b。就是解这个二元一次方程(num已知;枚举a和b,算得base>max(a,b)即可)
如果输入的num转化后是三位数,以base作为进制的话,转换为base进制就是num=a*base*base+b*base+c,就是枚举a,b,c算得base>max(a,b,c)即可。
如果输入的num转化后是四位数及以上,那么其base进制可以枚举的范围是:base>min(3,4,5,6),即base最小是4。而对于其他的情况,我们只用取一个适合的大小的上界,x1+x2*base+x3*base^2+x4*base^3+...>base+x1*base+x2*base^2+x3*base^3,其上界可以取num^(1/3)即可。
这样省了很多时间。
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<cmath>
using namespace std;
#define LL long long
LL getmax(LL a,LL b)
{
if(a>b) return a;
else return b;
}
int main ()
{
LL T,Tt;
scanf("%d",&T);
for(LL Tt=1;Tt<=T;Tt++)
{
LL num,x1,x2,x3,ans=0;
scanf("%I64d",&num);
//如果是3,4,5,6直接输出-1
if(num>=3 && num<=6) {printf("Case #%I64d: -1\n",Tt);continue;}
//转化为base进制后是二位 x1*base + x2 = num
for(x1=3;x1<=6;x1++)
for(x2=3;x2<=6;x2++)
{
if( (num-x2)%x1==0 && (num-x2)/x1>getmax(x1,x2) ) ans++;
}
//转换为base进制后是三位
// x1*base^2 + x2*base + x3 = num
for(x1=3;x1<=6;x1++)
for(x2=3;x2<=6;x2++)
for(x3=3;x3<=6;x3++)
{
LL a=x1,b=x2,c=x3-num;
LL derta=(LL)sqrt(b*b-4*a*c+0.5);
if(derta*derta!=b*b-4*a*c) continue;
if( (derta-b)%(2*a)) continue;
if( (derta-b)/(2*a)>getmax(x1,getmax(x2,x3))) ans++;
}
//其他
for(LL i=4;i*i*i<=num;i++) //之前把i定义成了int类型,TLE了,是int转LL的时候花了很多时间
{
LL t=num;
while(t)
{
if(t%i<3||t%i>6) break;
t=t/i;
}
if(!t) ans++;
}
printf("Case #%I64d: %I64d\n",Tt,ans);
}
}