※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。


Problem 74 「桁の階乗による連鎖」 †

145は各桁の階乗の和が145と自分自身に一致することで有名である.

1! + 4! + 5! = 1 + 24 + 120 = 145

169の性質はあまり知られていない. これは169に戻る数の中で最長の列を成す. このように他の数を経て自分自身に戻るループは3つしか存在しない.

169 → 363601 → 1454 → 169
871 → 45361 → 871
872 → 45362 → 872

どのような数からスタートしてもループに入ることが示せる.

例を見てみよう.

69 → 363600 → 1454 → 169 → 363601 (→ 1454)
78 → 45360 → 871 → 45361 (→ 871)
540 → 145 (→ 145)

69から始めた場合, 列は5つの循環しない項を持つ. また100万未満の数から始めた場合最長の循環しない項は60個であることが知られている.

100万未満の数から開始する列の中で, 60個の循環しない項を持つものはいくつあるか?

解法
7ケタが全部9でも254万程度で、8桁になっても280万程度です。
つまり多めに見積もっても260万程度までをメモ化しておけばよいと分かります。
これで十分間に合います。
今回もC++でPrologではありません。


#include<stdio.h>
#include<string.h>

char lens[2600000];
const int fact[10]={1,1,2,6,24,120,720,5040,40320,362880};

int toNextNum(int num){
	int re=0;
	while(num!=0){
		re+=fact[num%10];
		num/=10;
	}
	return re;
}
 
int search(int num){
	if(num==toNextNum(num)){
		lens[num]=0;
		return 0;
 	}
	if(lens[num]>=0){
		return lens[num];
	}else{
 		lens[num]=0;
		lens[num]=search(toNextNum(num))+1;
		if(lens[num]>60)lens[num]=60;
		return lens[num];
	}
} 

int main(){
	int ans=0;
	memset(lens,-1,sizeof(lens));
	for(int i=1;i<1000000;i++){
 		if(lens[i]>=0){
			ans+=(lens[i]>=60);
		}else{
			ans+=(search(i)>=60);
		}
	}
	printf("%d\n",ans);
}