我有一个代码从stdin读取(10 ^ 5)int(s)然后执行## i后输出它们在stdout上。我使用“setvbuf”&amp ;;来处理INPUT部分。使用“fgets_unlocked()”读取行,然后解析它们以获取所需的int(s)。 我有两个问题,我无法解决:
1。)因为我在stdout上打印了500万这花了很多时间:有什么方法可以减少这个(我尝试使用fwrite()但o / p打印出不可打印的字符,原因是因为这个原因using fread to read into int buffer)
2。)解析int(s)的输入后说'x'我实际上通过对循环中的no执行%(mod)来找到除数的数量。(参见下面的代码):也许这个也是我的代码超时的原因: 对此有任何建议改进。 非常感谢 这实际上来自http://www.codechef.com/problems/PD13
的问题# include <stdio.h>
# define SIZE 32*1024
char buf[SIZE];
main(void)
{
int i=0,chk =0;
unsigned int j =0 ,div =0;
int a =0,num =0;
char ch;
setvbuf(stdin,(char*)NULL,_IOFBF,0);
scanf("%d",&chk);
while(getchar_unlocked() != '\n');
while((a = fread_unlocked(buf,1,SIZE,stdin)) >0)
{
for(i=0;i<a;i++)
{
if(buf[i] != '\n')
{
num = (buf[i] - '0')+(10*num);
}
else
if(buf[i] == '\n')
{
div = 1;
for(j=2;j<=(num/2);j++)
{
if((num%j) == 0) // Prob 2
{
div +=j;
}
}
num = 0;
printf("%d\n",div); // problem 1
}
}
}
return 0;
}
答案 0 :(得分:2)
您可以比printf打印得快得多。
查看itoa()
,或编写自己的简单函数,将整数转换为ascii。
这是一个快速肮脏的itoa版本,应该可以快速用于您的目的:
char* custom_itoa(int i)
{
static char output[24]; // 64-bit MAX_INT is 20 digits
char* p = &output[23];
for(*p--=0;i/=10;*p--=i%10+0x30);
return ++p;
}
请注意,此功能有一些严格的内置限制,包括:
我纯粹是出于速度而写的,不是为了安全或方便。
答案 1 :(得分:2)
第2版基于@UmNyobe和@wildplasser的建议(见上述评论) 在线判断代码执行花了0.12秒和3.2 MB的内存。 我自己用2 * 10 ^ 5 int(输入)检查了1到5 * 10 ^ 5的范围,并执行了:
真实0m0.443s
用户0m0.408s
sys 0m0.024s
**请查看是否可以进行更多优化。
enter code here
/** Solution for the sum of the proper divisor problem from codechef **/
/** @ author dZONE **/
# include <stdio.h>
# include <math.h>
# include <stdlib.h>
# include <error.h>
# define SIZE 200000
inline int readnum(void);
void count(int num);
int pft[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709};
unsigned long long int sum[SIZE];
int k = 0;
inline int readnum(void)
{
int num = 0;
char ch;
while((ch = getchar_unlocked()) != '\n')
{
if(ch >=48 && ch <=57)
{
num = ch -'0' + 10*num;
}
}
if(num ==0)
{
return -1;
}
return num;
}
void count(int num)
{
unsigned int i = 0;
unsigned long long tmp =0,pfac =1;
int flag = 0;
tmp = num;
sum[k] = 1;
for(i=0;i<127;i++)
{
if((tmp % pft[i]) == 0)
{
flag =1; // For Prime numbers not in pft table
pfac =1;
while(tmp % pft[i] == 0)
{
tmp =tmp /pft[i];
pfac *= pft[i];
}
pfac *= pft[i];
sum[k] *= (pfac-1)/(pft[i]-1);
}
}
if(flag ==0)
{
sum[k] = 1;
++k;
return;
}
if(tmp != 1) // For numbers with some prime factors in the pft table+some prime > 705
{
sum[k] *=((tmp*tmp) -1)/(tmp -1);
}
sum[k] -=num;
++k;
return;
}
int main(void)
{
int i=0,terms =0,num = 0;
setvbuf(stdin,(char*)NULL,_IOFBF,0);
scanf("%d",&terms);
while(getchar_unlocked() != '\n');
while(terms--)
{
num = readnum();
if(num ==1)
{
continue;
}
if(num == -1)
{
perror("\n ERROR\n");
return 0;
}
count(num);
}
i =0;
while(i<k)
{
printf("%lld\n",sum[i]);
++i;
}
return 0;
}
答案 2 :(得分:1)
// Prob 2你的biggesr现在问题....你只是想找到除数的数量?
我的第一个建议是在某种程度上缓存你的结果......但这需要你开始时存储量的两倍:/。
您可以做的是事先生成素数列表(using the sieve algorithm)。理解列表中最大的数字N
并生成所有素数直到他的平方根是理想的。现在,对于列表中的每个数字,您希望将其表示作为因子的乘积,即
n = a1^p1 * a1^p2 *... *an^pn
然后sum of divisors将是。
((a1^(p1+1) - 1)/(a1 - 1))*((a2^(p2+1) - 1)/(a2-1))*...*((an^(pn+1) - 1)/(an-1))
要了解你有(对于n = 8)1+ 2 + 4 + 8 = 15 = (16 - 1)/(2 - 1)
它会大大提高速度,但整数分解(你真正做的是)真的很贵......
修改:
在您的链接中,最大值为5000000,因此您最多有700个素数
简单分解算法
void primedecomp(int number, const int* primetable, int* primecount,
int pos,int tablelen){
while(pos < tablelen && number % primetable[pos] !=0 )
pos++;
if(pos == tablelen)
return
while(number % primetable[pos] ==0 ){
number = number / primetable[pos];
primecount[pos]++;
}
//number has been modified
//too lazy to write a loop, so recursive call
primedecomp(number,primetable,primecount, pos+1,tablelen);
}
编辑:而不是计算,使用a^(n+1)
计算primepow = a; primepow = a*primepow;
在你有hashmap的C ++或java中会更清晰。在末尾
primecount
包含我上面谈到的pi
值。
即使看起来很可怕,也只会创建primetable
一次。现在这个算法
在最O(tablelen)
O(square root(Nmax))
中运行O(Nmax)
。你的初始
循环在{{1}}中运行。