SRM 369 500pt: AbsSequence
問題概要
ある数列の初項A[0]、第二項A[1]が与えられる。数列はA[n] = abs(A[n-1]-A[n-2])を満たす。第k項を求めよ、というクエリをN(<50)個程度処理せよ。数字は全て非負で10^18以下。
考えたこと
- 入力がまたstringで与えられて非常に鬱陶しい。この辺は今でもたまに感じる(グラフがvector
で与えられたり)。 - これそのうちループに落ちるんだよね。というかやってることってgcdの計算そのものだ。
- gcdのmodの代わりに引き算使ってるだけなので、アイデアはすぐ分かるんだけど実装面倒そう。
- ある状態の先頭2つA、Bがわかっているとき、B, A%Bまでは規則的に落ちそう。mapに節目だけ突っ込んでlower_boundで探す感じか。
- でもA,Bの大小関係とかあってやっぱり面倒くさい。
- 節目でA=Bになるまで愚直にシミュレーションしよう。
- 規則を考えよう。(A=x+k*B, B)の状態から3ターン経過で(A=x+(k-2)*B, B)に落ちる。
- なので節目をlower_boundで探してそこからの経過ターン数を3で割った場合分けして出すか。
- 流石にこの場合分けは不可避だろう。
- 書けた。出した。通った。
practiceで通ったコード
計算量は大雑把にO(N*log(A))位。
#include <vector> #include <string> #include <sstream> #include <map> #include <cstdio> #include <algorithm> #include <functional> using namespace std; typedef long long int64; struct AbsSequence { vector <string> getElements(string first, string second, vector <string> indices) { //データ変換 int64 A = string_to_int64(first), B = string_to_int64(second); vector<int64> result, idxs; const int N = indices.size(); for(int i=0; i<N; i++){ idxs.push_back( string_to_int64(indices[i]) ); } //前処理 map<int64, pair<int64,int64>, greater<int64> > dict; int64 cur = 0; dict[cur] = make_pair(A,B); while(A != 0 && B != 0){ int64 k = A/B; if(k<=1){ int64 C = abs(A-B); A = B; B = C; dict[++cur] = make_pair(A,B); } else{ cur += k/2*3; A = A%B + (k&1)*B; dict[cur] = make_pair(A,B); } } //本体 for(int i=0; i<N; i++){ int64 ans = 0; int64 tmp_turn = dict.lower_bound(idxs[i])->first; if(tmp_turn == idxs[i]){ ans = dict[tmp_turn].first; } else{ int64 shift = idxs[i] - tmp_turn; int64 res = shift%3; int64 skip = shift/3; A = dict[tmp_turn].first; B = dict[tmp_turn].second; if(A==0 || B==0){ if(res == 0){ ans = A; } else if(res == 1){ ans = B; } else{ ans = abs(A-B); } } else{ if(res == 0){ ans = A - skip*2*B; } else if(res == 1){ ans = B; } else{ ans = A - (skip*2+1)*B; } } } result.push_back(ans); } //データ変換 vector<string> ret; for(int i=0; i<N; i++){ ret.push_back( int64_to_string(result[i]) ); } return ret; } int64 string_to_int64(const string& a){ stringstream ss(a); int64 ret; ss >> ret; return ret; } string int64_to_string(const int64 x){ stringstream ss; ss << x; return ss.str(); } };