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


0<k<10^(11^12)な数kのうち、23で割り切れてかつ各桁の和が23になるkの数を答えよ。
答えは10^9で割った余りで答えよ。
計算時間3秒の解。


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

const int LIMIT=23;
const int LIMIT1=24;
const __int64 MOD=10000*10000*10;
const __int64 U=pow(11,6);
__int64 up=U*U;
__int64 mult;

void f(__int64 a[LIMIT1][LIMIT],__int64 b[LIMIT1][LIMIT],__int64 c[LIMIT1][LIMIT],int n,bool t){
	memset(c,0,LIMIT*LIMIT1*8);
	//a[桁和][23の倍数か]
	for(int i=0;i<=LIMIT;i++){
		//桁和
		for(int j=0;j<=i;j++){
			int p1=j;
			int p2=i-j;
			for(int k=0;k<LIMIT;k++){
				int p3=k;
				for(int l=0;l<LIMIT;l++){
					int p4;
					if(t==true){
						p4=(l*mult)%LIMIT;
					}else{
						p4=(l*n)%LIMIT;
					}
					c[i][(p3+p4)%LIMIT]=(c[i][(p3+p4)%LIMIT]+(a[p2][l]*b[p1][k]))%MOD;
				}
			}
		}
	}
	if(t==true){
		mult=(mult*n)%LIMIT;
	}
} 

int main(){
	__int64 a[LIMIT1][LIMIT];//a[桁和][23の倍数か]
	__int64 ans[LIMIT1][LIMIT],c[LIMIT1][LIMIT];

	memset(a,0,sizeof(a));

	for(int i=0;i<=9;i++)a[i][i]=1;

	bool isF=true;
	mult=10;
	int n=mult;
	while(up>0){
		if(up%2==1){
			if(isF==false){
				f(a,ans,c,n,true);
				memcpy(ans,c,sizeof(ans));
			}else{
				isF=false;
				memcpy(ans,a,sizeof(a));
			}
		}
		f(a,a,c,n,false);
		memcpy(a,c,sizeof(c));
		up/=2;
		n=(n*n)%LIMIT;
	}
	std::cout<<ans[23][0]<<"\n";
}
最終更新:2015年12月18日 02:03