标签:
#include<stdio.h> // 超时
int main(void)
{
int t, n, sum;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
sum = 0;
for(int fac = 1; fac <= n/2; fac++) // n的因子不可能大于n/2
{
if(n % fac == 0)
sum += fac;
}
printf("%d\n", sum);
}
return 0;
}
正如注释中写到的,该方法超时了,因此我们需要另觅良方来提高效率:可以枚举到√n,如果n有一个比它小的因子,那么必然有一个比它大的因子。
#include<stdio.h> // 优化
#include<math.h>
int main(void)
{
int t, n, sum;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
sum = 1;
// 写法一:for(int fac = 2; fac <= floor(sqrt(n)+0.5); fac++)直接超时,因为每次循环都得求一次sqrt.
// 写法二:int bound = floor(sqrt(n)+0.5);
// for(int fac = 2; fac <= bound; fac++) // 452MS.
// 写法三://280MS.对比可知,sqrt函数太耗时了.可以用乘法代替的话还是拒绝sqrt吧.
for(int fac = 2; fac*fac <= n; fac++)
{
if(n % fac == 0)
{
sum += fac;
if(fac*fac != n)
sum += n/fac;
}
}
printf("%d\n", sum);
}
return 0;
}
嗯?素数筛呢?没用吗?没用我介绍它干嘛:-,我们来试一下:
#include<stdio.h> // 素数筛,405MS
#include<math.h>
#include<string.h>
#define MAXN 500000
int prime[MAXN+10];
int main(void)
{
memset(prime, 0, sizeof(prime));
// 构造1-500000所有素数,0代表是素数,1代表不是素数
for(int i = 2; i*i <= MAXN; i++)
if(prime[i] == 0)
for(int j = i+i; j <= MAXN; j += i)
prime[j] = 1;
int t, n, sum;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
sum = 1;
if(prime[n] == 0)
;
else
{
for(int fac = 2; fac*fac <= n; fac++)
{
if(n % fac == 0)
{
sum += fac;
if(fac*fac != n)
sum += n/fac;
}
}
}
printf("%d\n", sum);
}
return 0;
}
可以看到,对比上一个程序,耗时有增无减,我只能找测试强度不够这茬了:-
在仔细思考的话,这题实际是素数筛法的变形,素数筛法是留下素数,而我们这题要求找因子的和,测试够强的话,借助素数筛法确实可以帮助我们提高程序的效率,不过这还只是间接地利用素数筛法的思想,我们可以直接应用其思想,直指目标。也就是直接求每个数的因子和放到数组中:
#include<stdio.h> // 根据素数筛的思想,来一个狠点的,78MS就AC
#include<string.h>
#define MAXN 500000
int sum_fac[MAXN+10];
int main(void)
{
for(int i = 2; i <= MAXN/2; i++) // MAXN的因子不可能超过MAXN/2
for(int j = i+i; j <= MAXN; j+=i)
{
sum_fac[j] += i; // 将i换做1,便可以求因子个数
}
int t, n;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
printf("%d\n", sum_fac[n]+1);
}
return 0;
}
最后,我们不讨论这个问题存不存在三角恋,自恋的问题,还是拿测试来说事吧,我测试了一下,求1的因子和时,按题意应该是0,不过测试数据中好像没有1,因为稍微修改一下程序,将1当作特例来处理,似乎任何值都可以过。
标签:
原文地址:http://www.cnblogs.com/xpjiang/p/4423016.html