プロジェクトオイラー問516

Problem 516 「5-スムーズトーシェント」 †

5-スムーズ数とは最大の素因数が5を超えないような数のことである.
5-スムーズ数はハミング数とも呼ばれる.
オイラーのトーシェント関数 φ(n) がハミング数となるような, Lを超えない数 n の値の和を S(L) としよう.
S(100)=3728.

S(10^12) を求めよ. 回答は 2^32 を法として答えよ.

夏の熱さでやられて簡単なことに気付かずループ。
時間がかかった。

解法
ファイ関数を求める公式から、条件を満たす数は2、3、5を素因数として持ち。
それより大きな素因数は一乗のものしか持たない。
そして大きな素因数は(2,3,5を素因数としてもつ数に1を足した)素数以外条件を満たせない。
これは公式から明らか。
後は1を忘れずに足すだけ。
コードがコンパクトになった。
こういう簡単な問題だけならいいんだけどね。
500番台は難しい問題のほうが多いな。


#include<stdio.h>
#include<iostream>
#include<math.h>
#include<set> 

//S(10000)=9586559

const __int64 LIMIT=pow(10,12);
const __int64 MOD=pow(2,32);
__int64 as[3]={2,3,5}; 

unsigned __int64 ans=0;
std::set<unsigned __int64> memo,memo2;


bool is_prime(__int64 n){
	for(__int64 i=2;i*i<=n;i+=1+(i&1)){
		if(n%i==0)return false;
	}
	return true;
}

void search(__int64 n,int p){
	if(n>LIMIT)return;
	if(n+1<=LIMIT){
		if(is_prime(n+1)&&(n+1>5)){
			memo2.insert(n+1);
		}
	}
	memo.insert(n);
	search(n*as[p],p);
 	if(p<2){
		search(n,p+1);
	}
}

void search2(unsigned __int64 a,std::set<unsigned __int64>::iterator& it,bool addOK){
 	ans+=(a*addOK);
	ans%=MOD;
	std::set<unsigned __int64>::iterator it2;
	if(it==memo2.end())return ;
	long double b=(*it);
	long double c=a;
	if(c*b>LIMIT)return ;
	it2=it;
 	it2++;
	search2(a*(unsigned __int64)b,it2,true);
	search2(a,it2,false);	
}


int main(){
	search(1,0);
	std::set<unsigned __int64>::iterator it,it2;
	for(it=memo.begin();it!=memo.end();it++){
		it2=memo2.begin();
		std::cout<<"\na="<<(*it)<<"\n";
 		search2((*it),it2,true);
	}
	std::cout<<ans<<"\n";
}
最終更新:2015年07月22日 09:04