A

论业界毒瘤之矩阵快速幂 + 快速乘。

因为%数是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

7

【输出样例】

22

9366795780274 

【提示】

对于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 \n", i - pos[f[i]][j]);
17                 return 0;
18             }
19         }
20         pos[f[i]].push_back(i);
21     }
22     return 0;
23 }
View Code

然后算法流程如下:

找到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 \n", i, getsum(i, 100000000000000));
 97     }
 98     LL x;
 99     while(scanf("%lld", &x)) {
100         printf("----%lld\n", 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 \n", i);
117         }
118     }
119     int p = 0;
120 
121     for(int i = 2; i <= 13; i++) {
122         //printf("i = %d \n", 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 \n", g);
128                 ///printf("%d == %d \n", getsum(g, po[i]), k % po[i]);
129                 if(getsum(g, po[i]) == k % po[i]) {
130                     //printf("%lld           pass \n", 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 }
AC代码

 

 

posted @ 2018-07-31 18:05  huyufeifei  阅读(180)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜