@description@

Fib数列为1,1,2,3,5,8...

求在Mod10^9+9的意义下,数字N在Fib数列中出现在哪个位置

无解输出-1

原题传送门。

@solution@

一个熟练的 OIer 选手应该能迅速发现 5 在模 10^9 + 9 意义下有二次剩余。考虑斐波那契通项公式:

\[f_i = \frac{1}{\sqrt{5}}((\frac{1 + \sqrt{5}}{2})^n - (\frac{1 - \sqrt{5}}{2})^n) = N
\]

不妨记 \(a = \frac{1 + \sqrt{5}}{2}, b = \frac{1 - \sqrt{5}}{2}\),则我们要解方程 \(a^n - b^n = \sqrt{5}N = K\)。

这个方程可解吗?注意 a, b 存在关系:\(a + b = 1, ab = -1\)。前一个显然不好用,我们用后一个:

\[a^n - (\frac{-1}{a})^n = K\\
a^{2n} - Ka^{n} - (-1)^n = 0\\
a^n = \frac{K \pm \sqrt{K^2 + 4\times(-1)^n}}{2}
\]

讨论一下 n 的奇偶可以解出 \(a^n\),然后 BSGS 即可。平方根也可 BSGS + 原根来解。

@accepted code@

#include <cstdio>
#include <vector>
#include <cassert>
#include <iostream>
#include <algorithm>
using namespace std; const int MOD = int(1E9) + 9;
const int INV2 = (MOD + 1) / 2;
const int INV5 = (MOD + 1) / 5;
const int SQ5 = 383008016;
const int A = 1LL*(MOD + 1 + SQ5)*INV2%MOD;
const int B = 1LL*(MOD + 1 - SQ5)*INV2%MOD;
const int C = 1LL*SQ5*INV5%MOD;
const int G = 13;
const int BLOCK = 32000;
const int HASHSIZE = 1000037;
const int MA = 133086171;
const int INVMA = 74832817;
const int GCD = 3; inline int add(int x, int y) {return (x + y >= MOD ? x + y - MOD : x + y);}
inline int sub(int x, int y) {return (x - y < 0 ? x - y + MOD : x - y);}
inline int mul(int x, int y) {return 1LL * x * y % MOD;} int pow_mod(int b, int p) {
int ret = 1;
for(int i=p;i;i>>=1,b=mul(b,b))
if( i & 1 ) ret = mul(ret, b);
return ret;
}
int fib(int n) {
int x = sub(pow_mod(A, n), pow_mod(B, n));
return mul(C, x);
} vector<pair<int, int> >h[HASHSIZE];
int hash_search(int x) {
int y = x % HASHSIZE;
for(int i=0;i<h[y].size();i++)
if( h[y][i].first == x )
return h[y][i].second;
return -1;
}
void hash_insert(int x, int k) {
int y = x % HASHSIZE;
for(int i=0;i<h[y].size();i++)
if( h[y][i].first == x )
return ;
h[y].push_back(make_pair(x, k));
}
void init() {
int p = pow_mod(G, BLOCK);
for(int i=1,q=p;i<=BLOCK;i++,q=mul(q,p))
hash_insert(q, i*BLOCK);
}
int bsgs(int x) {
if( x == 0 ) return -1;
int ret = MOD;
for(int i=1,q=G;i<=BLOCK;i++,q=mul(q,G)) {
int p = hash_search(mul(x, q));
if( p != -1 ) ret = min(ret, p - i);
}
assert(pow_mod(G, ret) == x);
return ret;
}
int msqrt(int x) {
if( x == 0 ) return 0;
int p = bsgs(x);
return p % 2 ? -1 : pow_mod(G, p / 2);
} int ans = -1;
void update(int x, int r) {
x = 1LL*(x / GCD)*INVMA%((MOD - 1) / GCD);
if( x % 2 == r )
if( ans == -1 || ans > x )
ans = x;
}
int main() {
int N, K; scanf("%d", &N), K = mul(N, SQ5), init(); int P = msqrt(add(mul(K, K), 4)); // even
if( P != -1 ) {
int k = bsgs(mul(add(K, P), INV2));
if( k != -1 && k % GCD == 0 ) update(k, 0);
k = bsgs(mul(sub(K, P), INV2));
if( k != -1 && k % GCD == 0 ) update(k, 0);
} P = msqrt(sub(mul(K, K), 4)); // odd
if( P != -1 ) {
int k = bsgs(mul(add(K, P), INV2));
if( k != -1 && k % GCD == 0 ) update(k, 1);
k = bsgs(mul(sub(K, P), INV2));
if( k != -1 && k % GCD == 0 ) update(k, 1);
} if( ans != -1 ) assert(fib(ans) == N);
printf("%d\n", ans);
}

@details@

因为几乎都是常数,可以预处理出来直接用。

话说这道题的主要难点是解方程那一块吧,感觉数学味儿多一点。

@bzoj - 5104@ Fib数列的更多相关文章

  1. BZOJ 5104 Fib数列(二次剩余+BSGS)

    斐波那契数列的通项: \[\frac{1}{\sqrt{5}}((\frac{1+\sqrt{5}}{2})-(\frac{1-\sqrt{5}}{2}))\] 设T=\(\sqrt{5}*N\),\ ...

  2. 【BZOJ5104】Fib数列(BSGS,二次剩余)

    [BZOJ5104]Fib数列(BSGS,二次剩余) 题面 BZOJ 题解 首先求出斐波那契数列的通项: 令\(A=\frac{1+\sqrt 5}{2},B=\frac{1-\sqrt 5}{2}\ ...

  3. FIB数列

    斐波那契级数除以N会出现循环,此周期称为皮萨诺周期. 下面给出证明 必然会出现循环 这是基于下面事实: 1. R(n+2)=F(n+2) mod P=(F(n+1)+F(n)) mod P=(F(n+ ...

  4. bzoj5104: Fib数列

    Description Fib数列为1,1,2,3,5,8... 求在Mod10^9+9的意义下,数字N在Fib数列中出现在哪个位置 无解输出-1 Input 一行,一个数字N,N < = 10 ...

  5. 动态规划之Fib数列类问题应用

    一,问题描述 有个小孩上楼梯,共有N阶楼梯,小孩一次可以上1阶,2阶或者3阶.走到N阶楼梯,一共有多少种走法? 二,问题分析 DP之自顶向下分析方式: 爬到第N阶楼梯,一共只有三种情况(全划分,加法原 ...

  6. UVaLive 3357 Pinary (Fib数列+递归)

    题意:求第 k 个不含前导 0 和连续 1 的二进制串. 析:1,10,100,101,1000,...很容易发现长度为 i 的二进制串的个数正好就是Fib数列的第 i 个数,因为第 i 个也有子问题 ...

  7. 【bzoj5118】Fib数列2 费马小定理+矩阵乘法

    题目描述 Fib定义为Fib(0)=0,Fib(1)=1,对于n≥2,Fib(n)=Fib(n-1)+Fib(n-2) 现给出N,求Fib(2^n). 输入 本题有多组数据.第一行一个整数T,表示数据 ...

  8. HDU3977 Evil teacher 求fib数列模p的最小循环节

    In the math class, the evil teacher gave you one unprecedented problem! Here f(n) is the n-th fibona ...

  9. 1022. Fib数列

    https://acm.sjtu.edu.cn/OnlineJudge/problem/1022 Description 定义Fib数列:1,1,2,3,5,8,13,…1,1,2,3,5,8,13, ...

随机推荐

  1. element-ui的el-table和el-form嵌套使用表单校验

    表格中嵌套使用表单验证 表格是el-table自动获取的后台数据,每行都有el-input的验证,这样一个rules的规则就不能匹配到每一行,所以要是用动态的prop和rules规则 需求如下,要对告 ...

  2. (数据科学学习手札84)基于geopandas的空间数据分析——空间计算篇(上)

    本文示例代码.数据及文件已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 在本系列之前的文章中我们主要讨论了g ...

  3. iOS 数组遍历过程中移除

    参考:https://blog.csdn.net/u011619283/article/details/53135502 常见crash 原因是数组在移除元素后,继续遍历会有越界问题. 解决思路: 遍 ...

  4. .Net基础之1——学前入门

    1..Net平台 2.C#编程语言 3..Net都能做什么 Winform桌面应用程序.Internet应用程序——ASP.Net(京东.淘宝.携程网)(主推). WP8手机开发.Unity 3D游戏 ...

  5. Git常用目录

    Git常用目录 // 初始化Git仓库 $ git init // 将代码添加到暂存区中 $ git add . // 将代码保存到仓库中 $ git commit -m "保存的说明&qu ...

  6. [C#学习教程-委托]001.大道至简之委托(代理),匿名函数,Lambda表达式

    引言:此文翻译自CodeProject上的同名文章<C# Delegates,Anonymous Methods, and Lambda Expressions>,在此一起Mark一下,此 ...

  7. Mysql基础(二)

    多表连接 #多表查询 /* sql99标准 等值连接 ①多表等值连接的结果为多表的交集部分 ② n个连接至少需要 n-1个连接 ③一般需要为表起别名 ④可以搭配前面介绍的所有子句的使用,比如排序,分组 ...

  8. MySQL如何有效的存储IP地址

    前几天,阿淼的一个朋友去面试,他回来告诉我,面试官问他 IP 地址是怎么存在数据库的?他当时也没多想,直接就回答的存字符串啊(心想:这么简单的问题,怕不是看不起我吧) 前面这段权当看看,毕竟 IP地址 ...

  9. jchdl - GSL实例 - Assign

    https://mp.weixin.qq.com/s/MtHR3iolPd5VQq6AUE-JPg   Assign是一个节点,把输入线直接赋值给输出线.在转换成Verilog时,这种类型的节点会直接 ...

  10. jchdl - GSL实例 - ComplementTwo(二的补码)

    https://mp.weixin.qq.com/s/Gh2xJJvfg1SlyuayK4LRyQ   二的补码指对二进制数的所有位数整体求补.二进制运算下0,1互为补数,n位二进制数a的补数为2^n ...