【问题描述】
从1− N中找一些数乘起来使得答案是一个完全平方数,求这个完全平方数最大可能是多少。
【输入格式】
第一行一个数字N。
【输出格式】
一行,一个整数代表答案对100000007取模之后的答案。
【样例输入】
7
【样例输出】
144
【样例解释】
但是塔外面有东西。
【数据规模与约定】
对于20%的数据,1<=N<=100。
对于50%的数据,1<=N<=5000。
对于70%的数据,1<=N<=10^5。
对于100%的数据,1<=N<=5*10^6。
________________________________________________________________
这个题并没有太好的办法,后来看了题解,才知道对N的阶乘进行质因数分解。于是用了筛法和快速幂,可是超时,只过了60分。于是学习了线性快速幂,时间少了,可还是60分,没解决根本问题。后来看了阶乘的质因数分解,很神奇!!!
将这个神奇的东西做一下介绍(引自网络):
求m!分解质因数后因子n的个数。
这道题涉及到了大数问题,如果相乘直接求的话会超出数据类型的范围。
下面给出一种效率比较高的算法,我们一步一步来。
m!=1*2*3*……*(m-2)*(m-1)*m
可以表示成所有和n倍数有关的乘积再乘以其他和n没有关系的
=(n*2n*3n*......*kn)*ohter other是不含n因子的数的乘积因为kn<=m 而k肯定是最大值所以k=m/n
=n^k*(1*2*......*k)*other
=n^k*k!*other
从这个表达式中可以提取出k个n,然后按照相同的方法循环下去可以求出k!中因子n的个数。
每次求出n的个数的和就是m!中因子n的总个数。
我的理解:
1、m!=1*2*3*……*m,里面肯定有n的整数倍,也就是1*2*……n……2*n……3*n……k*n……m;
2、里面有几个n的倍数就在M!中有几个n,于是m/n个;
3、可是还有些特殊情况,如n*n,n*n*n,这样在m/n的得数中再除n,再除n,再除n,……知道为0;
关于线性筛法要注意:
if(i%ss[j]==0)break;
__________________________________________________________________
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 const int m=5000001; 8 const int md=100000007; 9 int n,js=0; 10 long long ans=1; 11 long long sz[m],ss[m],cs[m]; 12 void sss()//线性筛法 13 { 14 memset(sz,-1,sizeof(sz)); 15 for(int i=2;i<m;i++) 16 { 17 if(sz[i])ss[js++]=i; 18 for(int j=0;j<js&&i*ss[j]<m;j++) 19 { 20 sz[i*ss[j]]=0; 21 if(i%ss[j]==0)break; 22 } 23 } 24 } 25 void fj(int i)//n的阶乘中含有多少个ss[i],时间复杂度可能是logxn(感觉是) 26 { 27 int x=ss[i]; 28 int k=n; 29 while(k) 30 { 31 k=k/x; 32 cs[i]+=k; 33 } 34 } 35 long long por(long long x,long long y)//快速幂 36 { 37 if(y%2)y=y-1; 38 x=x%md; 39 long long anss=1; 40 long long ds=x; 41 for(;y>0;y>>=1) 42 { 43 if(y&1)anss*=ds; 44 anss%=md; 45 ds=(ds%md)*(ds%md)%md; 46 } 47 return anss; 48 } 49 int main() 50 { 51 freopen("hao.in","r",stdin); 52 freopen("hao.out","w",stdout); 53 scanf("%d",&n); 54 sss(); 55 for(int i=0;i<js;i++) 56 fj(i); 57 for(int i=0;i<js;i++) 58 { 59 ans*=por(ss[i],cs[i]); 60 ans%=md; 61 } 62 cout<<ans; 63 fclose(stdout); 64 fclose(stdin); 65 return 0; 66 }