CS Academy Recursive String
リンク : https://csacademy.com/contest/archive/task/recursive-string/statement/
問題概要
f(0)="a",f(1)="b",f(2)="c",f(n)=f(n-1)+f(n-2)+f(n-3) であらわされる文字列を返す関数がある。N,Kが入力されるのでf(N)のK番目の値を出力せよ。
解説
N<=35より、全通りできるかなとか思ってしまった。
f(N)のサイズはフィボナッチと同様に線形時間でできる。K番目の文字さえわかればよいため、f(N)の文字列を実際に求める必要はない。もしK>f(N).size なら -1 を出力。そうでない場合は、f(N)のK番目ということは、f(N-1)かf(N-2)かf(N-3)のどこかに属する。それぞれの文字列の大きさのみに注目してf(N)のK番目がf(N-1)かf(N-2)かf(N-3)のどこに属するかわかると、最終的にf(0)かf(1)かf(2)のどこかに属することがわかる。
LL n, k,dp[40];
string str;
int main() {
cin >> n >> k;
dp[0] = 1, dp[1] = 1, dp[2] = 1;
rep(i, n) {
dp[i + 3] = dp[i] + dp[i + 1] + dp[i + 2];
}
if (dp[n] < k) {
cout << -1 << endl;
return 0;
}
LL i = n;
while (i > 2) {
if (k <= dp[i - 1])
i = i - 1;
else if (k <= dp[i - 1] + dp[i - 2])
k -= dp[i - 1], i = i - 2;
else
k -= dp[i - 1] + dp[i - 2], i = i - 3;
}
if (i == 0) cout << "a" << endl;
if (i == 1) cout << "b" << endl;
if (i == 2) cout << "c" << endl;
return 0;
}