プロジェクトオイラー問375暫定解


問題の確認。
Let Sn be an integer sequence produced with the following pseudo-random number generator:

S0 = 290797
Sn+1 = (Sn)^2 mod 50515093
Let A(i, j) be the minimum of the numbers Si, Si+1, ... , Sj for i ≤ j.
Let M(N) = ΣA(i, j) for 1 ≤ i ≤ j ≤ N.
We can verify that M(10) = 432256955 and M(10 000) = 3264567774119.

Find M(2 000 000 000).


とりあえずの解法。
計算時間24分の暫定解。
一分ルールは今のところ想像もつきません。
関数は最大でも50515093までの周期しか持たないことを利用して計算量を下げられる?




#include<stdio.h>
#include<map>
#include<iostream>

const int LIMIT=2000000000;
__int64 f(__int64 n){
	return (n*n)%50515093;
}

int main(){
	std::map<int,__int64> memo;
	std::map<int,__int64>::iterator it,it2;
	__int64 s=f(290797);
	memo[0]=0;
	memo[1]=s;
	__int64 ans=s;
	__int64 sum=s;
	for(int i=2;i<=LIMIT;i++){
		
		s=f(s);
		sum+=s;
		memo[i]=s;
		it=memo.lower_bound(i);
		it--;
		it2=it;
		it2--;
		if(i%1000000==0)std::cout<<i<<" "<<ans<<" "<<memo.size()<<"\n";
		while(it!=memo.begin()){
			__int64 p=(*it).first;
			__int64 p2=(*it2).first;
			__int64 n=(*it).second;
			if(n>=s){
				sum+=(p-p2)*(s-n);
				memo.erase(p);
				it=memo.lower_bound(p);
				it--;
				if(it==memo.begin())break;
				it2=it;
				it2--;
			}else{
				break;
			}
		}
		ans+=sum;
	}
	std::cout<<"ans"<<ans<<"\n";
}
最終更新:2015年12月15日 13:27