SRM 475 600pt: RabbitIncreasing
問題概要
a[0]=1, b[0]=1である。a[n+1]=b[n], b[n+1]=a[n]+b[n]、ただし、いくつかのnについてはb[n+1]=a[n]/2である。a[K]+b[K]をmod 10^9+9(=:P)で求める問題。K<10^7。
考えたこと
- (当時は行列計算実装している間に終わった記憶がある)
- 漸化式の形に落とすことはできた。
- mod Pの中で割り切れない可能性のある割り算ってどうするんだ?
- そもそも1とP+1では割った結果が違うんだから、mod Pの値だけでは情報が足りないことは分かる。
- でもそれ以上が分からない。
- 結局諦めてEditorialを読んだ。
- mod 2^55(55は割り算が生じる回数の上界)での値も覚えておけばよいらしい。なるほど賢い。
- この問題正解者が少なかったっぽい。
- 行列累乗でさらに計算量を落とすこともできる。面倒だけど。
practiceで通ったコード
計算量O(K)。
#include <vector> using namespace std; typedef unsigned long long uint64; const uint64 MOD = (int)(1e+9 + 9); const int MAX_K = (int)(1e+7); bool leave[MAX_K+1]; struct RabbitIncreasing { int getNumber(vector <int> leaving, int k) { if(leaving[0] == 1){ return 0; } for(int i=0; i<(int)leaving.size(); i++){ leave[leaving[i]] = true; } uint64 zero_mod = 1, zero = 1, one_mod = 0, one = 0; for(int y=2; y<=k; y++){ uint64 tmp_mod = one_mod, tmp = one; if(leave[y]){ if(zero%2 != zero_mod%2){ zero_mod += MOD; } one_mod = zero_mod / 2; one = zero / 2; } else{ one_mod = (one_mod + zero_mod) % MOD; one += zero; } zero_mod = tmp_mod; zero = tmp; } return (int)((zero_mod + one_mod) % MOD); } };