我现在已经24小时工作,试图优化它。问题是如何在大约8秒内找到10000000和1000万个测试用例中的数字因子的尾随零数。
代码如下:
#include<iostream>
using namespace std;
int count5(int a){
int b=0;
for(int i=a;i>0;i=i/5){
if(i%15625==0){
b=b+6;
i=i/15625;
}
if(i%3125==0){
b=b+5;
i=i/3125;
}
if(i%625==0){
b=b+4;
i=i/625;
}
if(i%125==0){
b=b+3;
i=i/125;
}
if(i%25==0){
b=b+2;
i=i/25;
}
if(i%5==0){
b++;
}
else
break;
}
return b;
}
int main(){
int l;
int n=0;
cin>>l; //no of test cases taken as input
int *T = new int[l];
for(int i=0;i<l;i++)
cin>>T[i]; //nos taken as input for the same no of test cases
for(int i=0;i<l;i++){
n=0;
for(int j=5;j<=T[i];j=j+5){
n+=count5(j); //no of trailing zeroes calculted
}
cout<<n<<endl; //no for each trialing zero printed
}
delete []T;
}
请通过建议新方法或建议对此方法进行一些修改来帮助我。
答案 0 :(得分:4)
使用以下定理:
如果p是素数,那么最高 分割n的p的力量! (N factorial)是[n / p] + [n / p ^ 2] + [n / p ^ 3] + ... + [n / p ^ k],其中k是 p <= n的最大功率,[x]是x的整数部分。
参考:http://planetmath.org/encyclopedia/PrimePowerDividingAFactorial.html
答案 1 :(得分:4)
最佳解决方案在O(log N)
时间运行,其中N
是您要为其找到零的数字。使用此公式:
Zeroes(N!) = N / 5 + N / 25 + N / 125 + ... + N / 5^k
,直到除法变为0.您可以在wikipedia上阅读更多内容。
例如,在C中,这将是:
int Zeroes(int N)
{
int ret = 0;
while ( N )
{
ret += N / 5;
N /= 5;
}
return ret;
}
这将在足够快的计算机上以8秒的速度运行。你可以通过使用查找表加快速度,虽然我不确定你有多少内存可用。
这是另一个建议:不存储数字,你不需要它们!读取时计算每个数字的零数。
如果这是针对在线评判的,根据我的经验,在线评委夸大了问题的时间限制,所以即使你有正确的算法,你也不得不诉诸丑陋的黑客。一个这样丑陋的黑客就是不使用诸如cin
和scanf
之类的函数,而是使用fread
在char数组中一次读取一堆数据,然后解析该数据(DON '虽然使用sscanf或stringstreams)并从中获取数字。丑陋,但通常更快。
答案 2 :(得分:1)
这个问题来自codechef。
http://www.codechef.com/problems/FCTRL
这个解决方案怎么样:
#include <stdio.h>
int a[] = {5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625, 48828125, 244140625};
int main()
{
int i, j, l, n, ret = 0, z;
scanf("%d", &z);
for(i = 0; i < z; i++)
{
ret = 0;
scanf("%d", &n);
for(j = 0; j < 12; j++)
{
l = n / a[j];
if(l <= 0)
break;
ret += l;
}
printf("%d\n", ret);
}
return 0;
}
任何优化???
答案 3 :(得分:1)
知道这已经超过2年了,但这是我的代码供将来参考:
#include <cmath>
#include <cstdio>
inline int read()
{
char temp;
int x=0;
temp=getchar_unlocked();
while(temp<48)temp=getchar_unlocked();
x+=(temp-'0');
temp=getchar_unlocked();
while(temp>=48)
{
x=x*10;
x+=(temp-'0');
temp=getchar_unlocked();
}
return x;
}
int main()
{
int T,x,z;
int pows[]={5,25,125,625,3125,15625,78125,390625,1953125,9765625,48828125,244140625};
T=read();
for(int i=0;i<T;i++)
{
x=read();
z=0;
for(int j=0;j<12 && pows[j]<=x;j++)
z+=x/pows[j];
printf("%d\n",z);
}
return 0;
}
它以0.13秒的速度运行
答案 4 :(得分:1)
这是我接受的解决方案。它的得分为1.51s,2.6M。不是最好的,但也许它可以帮助你。
#include <iostream>
using namespace std;
void calculateTrailingZerosOfFactoriel(int testNumber)
{
int numberOfZeros = 0;
while (true)
{
testNumber = testNumber / 5;
if (testNumber > 0)
numberOfZeros += testNumber;
else
break;
}
cout << numberOfZeros << endl;
}
int main()
{
//cout << "Enter number of tests: " << endl;
int t;
cin >> t;
for (int i = 0; i < t; i++)
{
int testNumber;
cin >> testNumber;
calculateTrailingZerosOfFactoriel(testNumber);
}
return 0;
}
答案 5 :(得分:-1)
#include <cstdio>
int main(void) {
long long int t, n, s, i, j;
scanf("%lld", &t);
while (t--) {
i=1; s=0; j=5;
scanf("%lld", &n);
while (i != 0) {
i = n / j;
s = s + i * (2*j + (i-1) * j) / 2;
j = j * 5;
}
printf("%lld\n", s);
}
return 0;
}
答案 6 :(得分:-2)
您显然已经知道正确的算法。代码中的瓶颈是使用cin / cout。处理非常大的输入时,与scanf相比,cin非常慢。
scanf也比读取输入的直接方法(如fread)慢,但使用scanf足以解决在线评委的几乎所有问题。
详细内容见Codechef FAQ,这可能值得先读一读;)