#include <sstream> #include <iostream> #include <vector> #include <string> using namespace std; struct matr_2x2 { long long a11, a12, a21, a22, modulo; matr_2x2(long long a11_, long long a12_, long long a21_, long long a22_, long long m_) : a11(a11_), a12(a12_), a21(a21_), a22(a22_), modulo(m_) { }; }; long long mul_by_modulo(long long a, long long b, long long modulo) { long long res = 0LL; while(b) { if(b & 1LL) { res += a; res %= modulo; } a <<= 1; a %= modulo; b >>= 1; } return res; } matr_2x2 mul(const matr_2x2 &A, const matr_2x2 &B) { #ifdef _DEBUG if(A.modulo != B.modulo) _DEBUG_ERROR("A.modulo != B.modulo"); #endif return matr_2x2( (mul_by_modulo(A.a11, B.a11, A.modulo) + mul_by_modulo(A.a12, B.a21, A.modulo)) % A.modulo, (mul_by_modulo(A.a11, B.a12, A.modulo) + mul_by_modulo(A.a12, B.a22, A.modulo)) % A.modulo, (mul_by_modulo(A.a21, B.a11, A.modulo) + mul_by_modulo(A.a22, B.a21, A.modulo)) % A.modulo, (mul_by_modulo(A.a21, B.a12, A.modulo) + mul_by_modulo(A.a22, B.a22, A.modulo)) % A.modulo, A.modulo ); }; matr_2x2 pow(matr_2x2 A, long long n) // A should be passed by copy { matr_2x2 res = matr_2x2(1LL, 0LL, 0LL, 1LL, A.modulo); // E, i.e. unitary matrix while(n) { if(n & 1LL) { res = mul(res, A); } A = mul(A, A); n >>= 1; } return res; } int main(int argc, char* argv[]) { string need_suffix; cin >> need_suffix; string cutted_suffix = need_suffix; if(cutted_suffix.size() > 5) { cutted_suffix.erase(0, cutted_suffix.size() - 5); } vector<vector<int> > reached_at(100000); long long modulo = 10; for(size_t i=1; i<cutted_suffix.size(); i++) modulo *= 10; int fib_0 = 0; int fib_1 = 1; int fib_2; int idx = 1; matr_2x2 FIB_MATRIX(1LL, 1LL, 1LL, 0LL, modulo); do { fib_2 = (fib_0 + fib_1) % ((int)modulo); fib_0 = fib_1; fib_1 = fib_2; idx++; #ifdef _DEBUG long long curr_fib_via_matrix = pow(FIB_MATRIX, idx).a21; if(fib_1 != curr_fib_via_matrix) _DEBUG_ERROR("fib_1 != curr_fib_via_matrix"); #endif reached_at[fib_1].push_back(idx); } while(!(fib_0==0 && fib_1==1)); long long suff_as_num, suff_as_num_cutted; stringstream istr(need_suffix); istr >> suff_as_num; suff_as_num_cutted = suff_as_num % modulo; if(reached_at[suff_as_num_cutted].empty()) { cout << "NIE\n"; } else if(need_suffix.size() <= 5) { cout << reached_at[suff_as_num][0] + (idx-1) << endl; } else { // need_suffix.size() >= 6 vector<long long> pos_of_needed_suffix_prev(reached_at[suff_as_num_cutted].size()); for(size_t i = 0; i < pos_of_needed_suffix_prev.size(); i++) pos_of_needed_suffix_prev[i] = (long long)reached_at[suff_as_num_cutted][i]; long long cycle_length = reached_at.size() + (reached_at.size() /2); for(size_t suff_len = 6; suff_len<=need_suffix.size(); suff_len++) { modulo *= 10LL; suff_as_num_cutted = suff_as_num % modulo; vector<long long> pos_of_needed_suffix_next; matr_2x2 FIB_MATRIX(1LL, 1LL, 1LL, 0LL, modulo); for(vector<long long>::iterator v = pos_of_needed_suffix_prev.begin(); v != pos_of_needed_suffix_prev.end(); v++) { for(long long num_cycles = 0LL; num_cycles < 10LL; num_cycles+=1LL) { long long found_fib = pow(FIB_MATRIX, *v + num_cycles*cycle_length).a21; if(found_fib == suff_as_num_cutted) pos_of_needed_suffix_next.push_back(*v + num_cycles*cycle_length); } } pos_of_needed_suffix_prev = pos_of_needed_suffix_next; cycle_length *= 10LL; } if(pos_of_needed_suffix_prev.empty()) cout << "NIE\n"; else cout << pos_of_needed_suffix_prev[0] + cycle_length << endl; } return 0; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | #include <sstream> #include <iostream> #include <vector> #include <string> using namespace std; struct matr_2x2 { long long a11, a12, a21, a22, modulo; matr_2x2(long long a11_, long long a12_, long long a21_, long long a22_, long long m_) : a11(a11_), a12(a12_), a21(a21_), a22(a22_), modulo(m_) { }; }; long long mul_by_modulo(long long a, long long b, long long modulo) { long long res = 0LL; while(b) { if(b & 1LL) { res += a; res %= modulo; } a <<= 1; a %= modulo; b >>= 1; } return res; } matr_2x2 mul(const matr_2x2 &A, const matr_2x2 &B) { #ifdef _DEBUG if(A.modulo != B.modulo) _DEBUG_ERROR("A.modulo != B.modulo"); #endif return matr_2x2( (mul_by_modulo(A.a11, B.a11, A.modulo) + mul_by_modulo(A.a12, B.a21, A.modulo)) % A.modulo, (mul_by_modulo(A.a11, B.a12, A.modulo) + mul_by_modulo(A.a12, B.a22, A.modulo)) % A.modulo, (mul_by_modulo(A.a21, B.a11, A.modulo) + mul_by_modulo(A.a22, B.a21, A.modulo)) % A.modulo, (mul_by_modulo(A.a21, B.a12, A.modulo) + mul_by_modulo(A.a22, B.a22, A.modulo)) % A.modulo, A.modulo ); }; matr_2x2 pow(matr_2x2 A, long long n) // A should be passed by copy { matr_2x2 res = matr_2x2(1LL, 0LL, 0LL, 1LL, A.modulo); // E, i.e. unitary matrix while(n) { if(n & 1LL) { res = mul(res, A); } A = mul(A, A); n >>= 1; } return res; } int main(int argc, char* argv[]) { string need_suffix; cin >> need_suffix; string cutted_suffix = need_suffix; if(cutted_suffix.size() > 5) { cutted_suffix.erase(0, cutted_suffix.size() - 5); } vector<vector<int> > reached_at(100000); long long modulo = 10; for(size_t i=1; i<cutted_suffix.size(); i++) modulo *= 10; int fib_0 = 0; int fib_1 = 1; int fib_2; int idx = 1; matr_2x2 FIB_MATRIX(1LL, 1LL, 1LL, 0LL, modulo); do { fib_2 = (fib_0 + fib_1) % ((int)modulo); fib_0 = fib_1; fib_1 = fib_2; idx++; #ifdef _DEBUG long long curr_fib_via_matrix = pow(FIB_MATRIX, idx).a21; if(fib_1 != curr_fib_via_matrix) _DEBUG_ERROR("fib_1 != curr_fib_via_matrix"); #endif reached_at[fib_1].push_back(idx); } while(!(fib_0==0 && fib_1==1)); long long suff_as_num, suff_as_num_cutted; stringstream istr(need_suffix); istr >> suff_as_num; suff_as_num_cutted = suff_as_num % modulo; if(reached_at[suff_as_num_cutted].empty()) { cout << "NIE\n"; } else if(need_suffix.size() <= 5) { cout << reached_at[suff_as_num][0] + (idx-1) << endl; } else { // need_suffix.size() >= 6 vector<long long> pos_of_needed_suffix_prev(reached_at[suff_as_num_cutted].size()); for(size_t i = 0; i < pos_of_needed_suffix_prev.size(); i++) pos_of_needed_suffix_prev[i] = (long long)reached_at[suff_as_num_cutted][i]; long long cycle_length = reached_at.size() + (reached_at.size() /2); for(size_t suff_len = 6; suff_len<=need_suffix.size(); suff_len++) { modulo *= 10LL; suff_as_num_cutted = suff_as_num % modulo; vector<long long> pos_of_needed_suffix_next; matr_2x2 FIB_MATRIX(1LL, 1LL, 1LL, 0LL, modulo); for(vector<long long>::iterator v = pos_of_needed_suffix_prev.begin(); v != pos_of_needed_suffix_prev.end(); v++) { for(long long num_cycles = 0LL; num_cycles < 10LL; num_cycles+=1LL) { long long found_fib = pow(FIB_MATRIX, *v + num_cycles*cycle_length).a21; if(found_fib == suff_as_num_cutted) pos_of_needed_suffix_next.push_back(*v + num_cycles*cycle_length); } } pos_of_needed_suffix_prev = pos_of_needed_suffix_next; cycle_length *= 10LL; } if(pos_of_needed_suffix_prev.empty()) cout << "NIE\n"; else cout << pos_of_needed_suffix_prev[0] + cycle_length << endl; } return 0; } |