惊讶N
时间限制(C/C++):1000MS/3000MS 运行内存限制:65536KByte
总提交:150 测试通过:51
总提交:150 测试通过:51
描述
大家都知道N的阶乘记作N!,就好像很惊讶,我就叫它惊讶N.
所以这题跟N!有关,给一个数N,求N!中所有质因数和
输入
多组测试数据,每组一行,每行有一个数字N(1<N<1000000)
输出
输出N!中所有质因数和
样例输入
2
3
4
样例输出
2
5
9
我这有三段代码:(傅总写的思路大概差不多。。这是他说的。。我是没看懂他代码...)
解法一:
#include<iostream>
#include<string.h>
#define N 1000010
using namespace std;
long long a[N];
int prime[N];
void get_prime(){
memset(prime,0,sizeof(prime)); //prime = 0
prime[0] = 1;
prime[1] = 1;
for(int i=2;i*i<=N;i++){
for(int j = i;j * i <= N ; j++)
prime[i*j] = 1;
}
}
long long func(int n){
if(!prime[n])
return n;
long long ans = 0;
while(prime[n]){
for(int i = 2;i * i <= n; i++){
if(!prime[i] && n % i == 0){
ans+=i;
n/=i;
break;
}
}
}
ans += n;
return ans;
}
void compute(){
get_prime();
a[0] = 0;
a[1] = 0;
a[2] = 2;
for(int i=3;i<N;i++)
a[i] = a[i-1] + func(i);
}
int main(){
int n;
compute();
while(cin>>n){
cout<<a[n]<<endl;
}
return 0;
}
总结:时间复杂度和空间复杂度都很高,主要就是把答案存在数组里先算出来,其中后一项是前一项加上项数的素因子和。(求项数的素因子和写的很麻烦)。反正这段代码不太好。。。。
代码二:
#include <iostream>
#include <string.h>
#define N 1000010
long long ans[N];
using namespace std;
void compute(){
memset(ans,0,sizeof(ans));
for(int i=0;i<=N;i++)
ans[i] = i;
for(int i = 2;i * i <= N ; i++){
for(int j = i; i * j <= N;j++)
ans[i * j] = ans[i] + ans[j]; //*************
}
for(int i=2;i<N;i++)
ans[i+1] +=ans[i];
}
int main(){
int n;
compute();
while(cin>>n){
cout<<ans[n]<<endl;
}
return 0;
}
总结:主要计算过程是在compute里。。先把答案数组赋值(其实是给素数赋值,因为合数部分在后面的循环里会被覆盖),根据算数基本定理,所有不是素数的数都可以用唯一的素数积序列表示,所以有了加标记的那一句。积的值是因子的和。(两重循环里的内容和素数筛选法有些像,i*j可以表示N之内的所有和数。i 和 j 要么是素数,要么是合数,如果是合数的话ans[]则是对应合数的素因子和,两项相加即可)。