参考博客:WSY大佬的做法
【题解】:
其实看到题目我就知道这个结论了,这个是我们小学课本上面的一个“完美数”。
没有规律可言。(当时比赛时候我是直接上网找到,其实不太道德,主要是看到太多人在10分钟内过了)
主要是看了WSY对于这个题目的执着,我自己也写了一遍。
【基本思想】
1、Euler把所有素数筛选出来
2、用唯一分解定理把所有的 质因数 与其 对应的 个数挑出来。
3、利用公式推出:
利用等比数列求和得到:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e5;
const int M = 1e5;
bitset <N> is_prime;
int prime[M],p_cnt;
ll qpow(ll a,ll b){
ll ans = 1 ;
while( b ){
if( b&1 ) ans = ans *a ;
a = a * a ;
b>>=1 ;
}
return ans ;
}
void Euler(){
is_prime.set();
for(ll i=2;i<N;i++){
if( is_prime[i] ){
prime[p_cnt++] = i;
}
for(ll j=0;j<p_cnt && i*prime[j]<N ;j++){
is_prime[ i*prime[j] ] = 0;
if( i%prime[j] == 0 ){
break;
}
}
}
}
ll P[100],K[100];
int main()
{
Euler();
for(int i=0;i<10;i++){
printf("%d\n",prime[i]);
}
int cnt = 0 ;
for(ll i=2;cnt<5;i++){
memset(P,0,sizeof(P));
memset(K,0,sizeof(K));
ll x = i,tx = i;
int tot = 0 ;
for( int j=0; j<p_cnt && tx >= prime[j]*prime[j] ; j++){
if( tx % prime[j] == 0 ) {
P[tot] = prime[j];
while( tx%prime[j]==0 ) {
K[tot]++;
tx/=prime[j];
}
tot++;
}
}
if( tx != 1 ){
P[tot] = tx;
K[tot] ++ ;
tot++;
}
ll tmp = 1;
for(int j=0;j<tot;j++){
tmp = tmp * (qpow(P[j],K[j]+1)-1)/(P[j]-1) ;
}
/*if( i==6 ){
for(int j=0;j<tot;j++){
printf("( %lld , %lld )\n",P[j],K[j]);
}
printf("Tmp :%lld\n",tmp);
}*/
if (tmp == x<<1 ){
printf("%lld\n",x);
cnt++;
}
}
return 0;
}
我的方法主要是用到了推导式:耗时66s
但是SY兄的写法更加简洁:耗时73s
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+7;
bool vis[maxn];
int prim[maxn],cnt;
void sprim(){
for(int i=2;i<maxn;i++){
if(!vis[i])prim[cnt++] = i;
for(int j=0;j<cnt && prim[j]*i<maxn;j++){
vis[prim[j]*i] = 1;
if(i%prim[j] == 0)break;
}
}
}
int main(){
sprim();
//for(int i=0;i<20;i++)printf("%d\n",prim[i]);
for(ll i=1;;i++){
ll x = 1,ti = i;
for(int j=0;j<cnt && 1ll*prim[j]*prim[j]<=ti;j++){
if(ti%prim[j] == 0){
ll p = prim[j];
ll tmp = 1;
while(ti%prim[j] == 0)
tmp += p,p *= prim[j],ti /= prim[j];
x *= tmp;
}
}
if(ti != 1)
x *= (1+ti);
if(x == 2*i)printf("%lld\n",i);
}
return 0;
}