论业界毒瘤之矩阵快速幂 + 快速乘。
因为%数是1e13爆long long了所以要快速乘...不会O(1)的就写了个O(logn)的。
这个溢出害我调了半天...
【题目描述】斐波那契数列满足f[0]=0,f[1]=1,f[i]=f[i-1]+f[i-2](i>=2)。已知f[i]对1e13取模的结果k,求最小的可能的i。无解输出-1。 【输入】输入包含一个非负整数k。 【输出】输出一个整数,为最小的可能的i。无解输出-1。 【输入样例】17711 【输出样例】22 【提示】对于100%的数据点,0<=k<1e13。 |
解:若 x % 1e13 == k 那么 x % d == k % d (d | 1e13)
由这个性质我们可以十进制拆分。
由于斐波那契数列数列的某个性质:对k取模时循环节不会超过6k
我们搞了个循环节表出来:
10 60
100 300
1000及以上 1500及以上
这里是找循环节的代码。
1 #include <cstdio> 2 #include <vector> 3 const int N = 1000010; 4 std::vector<int> pos[N]; 5 int f[N]; 6 int main() { 7 int n; 8 scanf("%d", &n); 9 f[0] = 0; 10 f[1] = 1; 11 pos[1].push_back(1); 12 for(int i = 2; ; i++) { 13 f[i] = (f[i - 1] + f[i - 2]) % n; 14 for(int j = 0; j < pos[f[i]].size(); j++) { 15 if(f[pos[f[i]][j] - 1] == f[i - 1]) { 16 printf("find:%d ", i - pos[f[i]][j]); 17 return 0; 18 } 19 } 20 pos[f[i]].push_back(i); 21 } 22 return 0; 23 }
然后算法流程如下:
找到60以内对10取模结果为k % 10的数。
对每个数,在300范围内加60,判断是不是%100结果为k % 100
对每个数,在1500内加300,判断%1000结果是不是k % 1000
...
直到%1e13
矩阵快速幂有剧毒...
1 #include <cstdio> 2 #include <algorithm> 3 #include <vector> 4 #include <cstring> 5 typedef long long LL; 6 const int N = 100010; 7 8 inline LL m(LL a, LL b, LL p) { 9 a %= p; 10 b %= p; 11 LL ans = 0; 12 while(b) { 13 if(b & 1) { 14 ans = (ans + a) % p; 15 } 16 a = (a + a) % p; 17 b = b >> 1; 18 } 19 return ans; 20 } 21 LL b[3][3], a[3][3], c[3][3], ans[3][3]; 22 inline void mulself(LL p) { 23 memset(b, 0, sizeof(b)); 24 for(int i = 1; i <= 2; i++) { 25 for(int j = 1; j <= 2; j++) { 26 for(int k = 1; k <= 2; k++) { 27 b[i][j] += m(a[i][k], a[k][j], p) % p; 28 b[i][j] %= p; 29 } 30 } 31 } 32 std::swap(a, b); 33 return; 34 } 35 36 inline void mula(LL p) { 37 memset(b, 0, sizeof(b)); 38 for(int i = 1; i <= 2; i++) { 39 for(int j = 1; j <= 2; j++) { 40 for(int k = 1; k <= 2; k++) { 41 b[i][j] += m(ans[i][k], a[k][j], p) % p; 42 b[i][j] %= p; 43 } 44 } 45 } 46 std::swap(b, ans); 47 return; 48 } 49 50 inline void mulc(LL p) { 51 memset(b, 0, sizeof(b)); 52 for(int j = 1; j <= 2; j++) { 53 for(int k = 1; k <= 2; k++) { 54 b[1][j] += m(c[1][k], ans[k][j], p) % p; 55 b[1][j] %= p; 56 } 57 } 58 std::swap(b, c); 59 return; 60 } 61 62 inline LL getsum(LL k, LL p) { 63 if(k == 0) { 64 return 0; 65 } 66 if(k == 1) { 67 return 1; 68 } 69 k--; 70 memset(a, 0, sizeof(a)); 71 memset(c, 0, sizeof(c)); 72 memset(ans, 0, sizeof(ans)); 73 a[1][2] = 1; 74 a[2][1] = 1; 75 a[2][2] = 1; 76 ans[1][1] = 1; 77 ans[2][2] = 1; 78 c[1][2] = 1; 79 while(k) { 80 if(k & 1) { 81 mula(p); 82 } 83 mulself(p); 84 k = k >> 1; 85 } 86 mulc(p); 87 return c[1][2]; 88 } 89 90 91 std::vector<LL> v[2]; 92 LL d[20], po[20]; 93 94 int main() { 95 /*for(int i = 1; i <= 66; i++) { 96 printf("%d %lld ", i, getsum(i, 100000000000000)); 97 } 98 LL x; 99 while(scanf("%lld", &x)) { 100 printf("----%lld ", getsum(x, 10000000000)); 101 }*/ 102 103 LL k; 104 scanf("%lld", &k); 105 d[1] = 60; 106 d[2] = 300; 107 po[2] = 100; 108 for(LL i = 3, t = 1000; i <= 15; i++, t = t * 10) { 109 d[i] = t + (t >> 1); 110 po[i] = t; 111 } 112 113 for(int i = 0; i <= 60; i++) { 114 if(getsum(i, 10) == k % 10) { 115 v[0].push_back(i); 116 //printf("%dth ", i); 117 } 118 } 119 int p = 0; 120 121 for(int i = 2; i <= 13; i++) { 122 //printf("i = %d ", i); 123 p = p ^ 1; 124 v[p].clear(); 125 for(int j = 0; j < v[!p].size(); j++) { 126 for(LL g = v[!p][j]; g <= d[i]; g += d[i - 1]) { 127 //printf("%lld is find ", g); 128 ///printf("%d == %d ", getsum(g, po[i]), k % po[i]); 129 if(getsum(g, po[i]) == k % po[i]) { 130 //printf("%lld pass ", g); 131 v[p].push_back(g); 132 } 133 } 134 } 135 if(!v[p].size()) { 136 printf("-1"); 137 return 0; 138 } 139 } 140 141 LL ans = 1ll << 62; 142 for(int i = 0; i < v[p].size(); i++) { 143 ans = std::min(ans, v[p][i]); 144 } 145 printf("%lld", ans); 146 return 0; 147 }