题目地址:
http://www.8zoj.tk/JudgeOnline/problem.php?id=3085
题意:
将一个正整数i的约数个数记为g(i),如g(1)=1,g(2)=2,g(6)=4。
如果对于一个正整数k,对于任意正整数i<k,均有g(k)>g(i),则k被称为反质数。
比如说1,2,4,6,12就是前5个反质数。
现在给定一个N,求N以内最大的反质数(N<=10^100)。
一个数的质因数分解形式为:
n=p_1^a_1*p^2^a_2*p_3^a_3*...*p_k^a_k
则n的约数个数为
g(n)=(a_1+1)*(a_2+1)*(a_3+1)*...*(a_n+1)
显然一个数是反质数,它的质因子一定是2,3,5,7,...,p_k的连续的一段,且2的指数>=3的指数>=5的指数>=7的指数,以此类推。要不然我们可以构造出一个更小的约数一样多的数。
用这个性质搜索可以通过10^15左右的数据,但是数据范围n<=10^100,怎么办呢?
通过观察小数据可以发现虽然用到了很多质数但大多数的次数是1,次数>=2的只有2、3、5、7等少数几个,这样我们枚举最大的质数,并且只枚举次数>2的质数,可以使速度提升,不过10^100还是过不了。
于是我就通过实验得出2的指数<=13,3的指数<=9,5的指数<=5。结果擦限AC了!O_O
注意用log是不行的,会有精度问题,必须用高精度。
OTZ SHUXK!求正解!!!!
CODE:
#include<cstdio> #include<cmath> #include<cstring> #include<cctype> using namespace std; const int P=350,N=30,MOD=10000; struct bigint{ int a[N]; int &operator[](int x){return a[x];} bigint(){ memset(a,0,sizeof(a)); a[0]=a[1]=1; } void print(); }; inline bool operator==(bigint a,bigint b){ if(a[0]!=b[0]) return false; for(int i=a[0];i;i--) if(a[i]!=b[i]) return false; return true; } inline bool operator>(bigint a,bigint b){ if(a[0]>b[0]) return true; if(a[0]<b[0]) return false; for(int i=a[0];i;i--) if(a[i]>b[i]) return true; else if(a[i]<b[i]) return false; return false; } inline bigint operator*(bigint a,int b){ for(int i=a[0];i;i--){ a[i]*=b; a[i+1]+=a[i]/MOD; a[i]%=MOD; } while(a[a[0]+1]) a[0]++; return a; } inline void bigint::print(){ printf("%d",a[a[0]]); for(int i=a[0]-1;i;i--) printf("%.4d",a[i]); printf("\n"); } int tot,f[P],p[P],st[P],ast[P],dep; //long double ans,y; bigint ans,y; bigint n; unsigned long long lt=1,mlt; int max(int a,int b){return a>b?a:b;} void getprime(){ for(int i=2;i<=P;i++){ if(!f[i]) p[++tot]=i; for(int j=1;j<=tot;j++){ if(i*p[j]>P) break; f[i*p[j]]=true; if(!(i%p[j])) break; } } } void search(int x,int max,bigint y,long long lt){ if(y>n) return; if(x==2&&max>9) max=9; if(x>=3&&max>5) max=5; if(x>dep){ if(lt>mlt||mlt==lt&&ans>y) mlt=lt,ans=y; return; } for(int i=1;i<=max;i++){ y=y*p[x]; search(x+1,i,y,lt*(i+1)); } } // 6 int main(){ //freopen("a.in","r",stdin); int i=0; int s[200]; getprime(); n[0]=n[1]=0; for(char c=getchar();isdigit(c);c=getchar()) s[++i]=c-48; for(int j=i;j>0;j-=4){ int tmp=0; for(int k=max(j-3,1);k<=j;k++) tmp=tmp*10+s[k]; n[++n[0]]=tmp; } bigint x; long double lx=0; for(dep=1;dep<=10;dep++) search(1,9,bigint(),1); //scanf("%lld",&n); dep=10; for(long long i=10,y=1;n>x;i++,x=x*p[i],y*=2) search(1,13,x,y); ans.print(); //printf("%lld\n",mlt); return 0; }