求x!在k进制下后缀和的个数
20分:
求十进制下的x!后缀和的个数
40分:
高精求阶乘,直接模拟过程 (我不管反正我不打,本蒟蒻最讨厌高精了)
60分
利用一个定理(网上有求x!在10进制、2进制下后缀和的个数的题,原理一样)
证明:(转自http://www.cnblogs.com/dolphin0520/)
求n的阶乘某个因子a的个数,如果n比较小,可以直接算出来,但是如果n很大,此时n!超出了数据的表示范围,这种直接求的方法肯定行不通。其实n!可以表示成统一的方式。
n!=(k^m)*(m!)*a 其中k是该因子,m=n/k,a是不含因子k的数的乘积
下面推导这个公式
n!=n*(n-1)*(n-2)*......3*2*1
=(k*2k*3k.....*mk)*a a是不含因子k的数的乘积,显然m=n/k;
=(k^m)*(1*2*3...*m)*a
=k^m*m!*a
接下来按照相同的方法可以求出m!中含有因子k的个数。
因此就可以求除n!中因子k的个数
上代码:
long long fac(long long x,long long y)
{
if (x<y)
return ;
else
return x/y+fac(x/y,y);
}
比如样例:求10!在40进制下后缀和的个数
X!转40进制只需不停地除以40,所以后缀零的个数等于x!能整除40 的个数。那么决定x!能整除多少个40的原因在于40的质因子(40=2*2*2*5=2^3+5^1),所以只要求在x!中40的某一质因子出现的次数,最后求出最少出现次数就行。根据质因子分解计算k的质因子p在x!中出现的次数:
可分解为x!=x*p^e的形式,e=x/p + x/p^2 + x/p^3+ ……,根据这个公式就能写出以下函数
再上个代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#define N 3000001
using namespace std;
long long a[N],b[N];//a数组存k的质因子,b数组存k的某质因子的个数
long long sum;
long long n,k;
long long ans=0x7fffffffffffffff,temp;
void fenjie(long long s) //求质因子及个数 (大概不需要解释了吧。。。)
{
long long i,j=;
for (i=;i*i<=s;i++)
if (s%i==)
{
long long count=;
a[j]=i;
while (s%i==)
{
count++;
s/=i;
}
b[j++]=count;
}
if (s>)
{
a[j]=s;
b[j++]=;
} //可能容易遗漏,即k本身是质数
sum=j;
} long long fac(long long x,long long y)
{
if (x<y)
return ; //判断x是否小于y,若小于,结束统计(否则会一直做下去)
else
return x/y+fac(x/y,y); //统计n!中a[i]出现的次数
} int main()
{
while (scanf("%lld%lld",&n,&k)==) //多组数据嘿嘿嘿(反正有人因为这个没分)
{
fenjie(k);
for(int i=;i<sum;i++)
{
temp=fac(n,a[i]);
temp/=b[i]; //注意,k可以分解为多个a[i],所以temp还要再除以a[i]的个数
ans=ans>temp?temp:ans;
}
printf("%lld\n",ans);
}
return ;
}
100分:
洛谷给出的终极巨无霸正解要用到Pollard rho算法来求k的质因子及其个数(反正我不会,而且代码超级长),我直接用了博客上的模板提交,发现确实不超时了,但莫名奇妙地wa了三个点。。。反正赛后改了数据还是ac了。