Description

农夫栋栋近年收入不景气,正在他发愁如何能多赚点钱时,他听到隔壁的小朋友在讨论兔子繁殖的问题。
问题是这样的:第一个月初有一对刚出生的小兔子,经过两个月长大后,这对兔子从第三个月开始,每个月初生一对小兔子。新出生的小兔子生长两个月后又能每个月生出一对小兔子。问第n个月有多少只兔子?
聪明的你可能已经发现,第\(n\)个月的兔子数正好是第\(n\)个\(Fibonacci\)(斐波那契)数。栋栋不懂什么是Fibonacci数,但他也发现了规律:第\(i+2\)个月的兔子数等于第\(i\)个月的兔子数加上第\(i+1\)个月的兔子数。前几个月的兔子数依次为:
\(1\;1\;2\;3\;5\;8\;13\;21\;34 \cdots\)
栋栋发现越到后面兔子数增长的越快,期待养兔子一定能赚大钱,于是栋栋在第一个月初买了一对小兔子开始饲养。
每天,栋栋都要给兔子们喂食,兔子们吃食时非常特别,总是每k对兔子围成一圈,最后剩下的不足\(k\)对的围成一圈,由于兔子特别害怕孤独,从第三个月开始,如果吃食时围成某一个圈的只有一对兔子,这对兔子就会很快死掉。
我们假设死去的总是刚出生的兔子,那么每个月的兔子数仍然是可以计算的。例如,当\(k=7\)时,前几个月的兔子数依次为:
\(1\;1\;2\;3\;5\;7\;12\;19\;31\;49\;80 \cdots\)
给定\(n\),你能帮助栋栋计算第\(n\)个月他有多少对兔子么?由于答案可能非常大,你只需要告诉栋栋第\(n\)个月的兔子对数除\(p\)的余数即可。

Input

输入一行,包含三个正整数\(n, k, p\)。

Output

输出一行,包含一个整数,表示栋栋第\(n\)个月的兔子对数除p的余数。

Sample Input

6 7 100

Sample Output

7

HINT

\(1 \le N \le 10^{18}\)
\(2 \le K \le 10^{6}\)
\(2 \le P \le 10^9\)

一道很好的矩阵乘法的题目,综合性感觉蛮强的。

以\(k=7\)为例,考虑\(f[i]%k\)组成的序列:
1,1,2,3,5,0,
5,5,3,0,
3,3,6,2,0,
2,2,4,6,3,2,5,0,5,5,3,0,
3,3,6,2,0,
\(\cdots\)

把减\(1\)得\(0\)的位置标出,并以这些\(0\)为界分段,可以发现:
①每段开头必为相同两数,它恰是上一段的最末一位非\(0\)数;由于总共只有\(k-1\)种余数,所以不超过\(k\)段就会出现循环(如果有的话),比如上面\(k=7\)时的第\(3,4\)段就是循环节。
②记斐波那契数列为\(fib[i]\)。假如某段段首数字为\(x\),那么这一段内第i个数即为\(x \times fib[i]%k\)。若记这一段长度为\(len\),则有\(x \times fib[len] \equiv 1(mod k)\)。

现在我们试图找到整个数列的循环结构:根据上式,①求x的逆元得到\(fib[len]\),②由\(fib[len]\)得知\(len\),③用\(x \times fib[len-1]%k\)算出下一段的段首,重复操作直到发现循环(或者发现这一段永远不终止)。
至于具体实现:①扩欧或者欧拉定理②预处理\(indfib[y]\)数组,表示斐波那契数列中模\(k\)余\(y\)的数第一次出现的下标(开头的两个1不算)③预处理\(fib[i]\)模\(k\)的值。有一个结论:斐波那契数列模\(k\)后一定是0,1,1开头的纯循环,而且这个循环节的长度$ \le 6k\((不知具体怎么证。。),所以只需暴力算\)fib\(数组并同时记录\)indfib[]\(,发现循环即停止。 注意,假如第①步不存在逆元,或者第②步不存在符合的\)len$,那么这一段将永远不会终止(比如k=8时就是这样),那么整个数列就不存在循环了(可以视作最后一段的长度为无穷大)。

接下来考虑如何用矩阵乘法计算\(f[n]%p\)。
两个重要矩乘:

分别记这两个\(3 \times 3\)矩阵为\(A,B\)。令初始矩阵为,通过对其不断右乘\(A\)和\(B\)便能实现累加、减\(1\)两种操作。对于分出的每一段算出一个矩阵\(A^{len} \times B\),表示这一段的“效果”。

接下来是喜闻乐见的分类讨论时间:假如整个数列是循环的,判断第n项是否在混循环的那部分里,若是则直接把前面几段乘起来,n所在这一段的零头直接用A的次幂算;若不是则先把混循环全部乘起来,然后把循环节全部乘起来,算出循环次数再快速幂,然后再像刚才一样算零头乘上去。若数列不循环倒方便些,也与上面类似,不多说了;如果长度无限,直接矩乘累加即可。

上述内容引自http://jcvb.is-programmer.com/posts/39528.html。

最后贴一份自己的代码:

#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std;typedef long long ll;
#define maxn (1000010)
ll n,K,p,fib[10000010],len[maxn],indfib[maxn],inv[maxn];
bool vis[maxn];struct Matrix
{ll a,b; ll s[4][4];Matrix () { memset(s,0,sizeof(s)); }friend inline Matrix operator * (const Matrix &x,const Matrix &y){Matrix z; z.a = x.a; z.b = y.b;for (ll i = 1;i <= z.a;++i)for (ll j = 1;j <= z.b;++j)for (ll k = 1;k <= x.b;++k)(z.s[i][j] += x.s[i][k]*y.s[k][j]%p)%=p;return z;}
}save[maxn];inline ll exgcd(ll a,ll b,ll c)
{if (a == 0) return -1;else if (c % a == 0) return c/a;ll t = exgcd(b % a,a,((-c % a)+a)%a);if (t == -1) return -1;return (t*b+c)/a;
}inline Matrix qsm(Matrix x,ll y)
{Matrix ret;ret.a = ret.b = x.a; ret.s[1][1] = ret.s[2][2] = ret.s[3][3] = 1;for (;y;y >>= 1,x = x*x)if (y & 1) ret = ret*x;return ret;
}int main()
{freopen("2432.in","r",stdin);freopen("2432.out","w",stdout);scanf("%lld %lld %lld",&n,&K,&p);fib[1] = fib[2] = 1;for (ll i = 3;;++i){fib[i] = fib[i-1] + fib[i-2];if (fib[i] >= K) fib[i] -= K;if (!indfib[fib[i]]) indfib[fib[i]] = i;if (fib[i] == 1&&fib[i-1] == 1) break;}Matrix ans,mul,dec; bool sign = false;ans.a = 1; ans.b = 3; ans.s[1][1] = ans.s[1][3] = 1;mul.a = mul.b = 3; mul.s[1][2] = mul.s[2][1] = mul.s[2][2] = mul.s[3][3] = 1;dec.a = dec.b = 3; dec.s[1][1] = dec.s[2][2] = dec.s[3][3] = 1; dec.s[3][2] = -1;for (ll t = 1;n;){if (!inv[t]) inv[t] = exgcd(t,K,1);if (inv[t] == -1) { ans = ans*qsm(mul,n); n = 0; }else{if (!vis[t]||sign){vis[t] = true;if (!indfib[inv[t]]){ans = ans*qsm(mul,n); n = 0;}else{len[t] = indfib[inv[t]];if (n >= len[t]){n -= len[t];save[t] = qsm(mul,len[t])*dec;ans = ans*save[t];(t *= fib[len[t]-1])%=K;}else { ans = ans*qsm(mul,n); n = 0; }}}else{ll cnt = 0; Matrix ret; ret.a = ret.b = 3; ret.s[1][1] = ret.s[2][2] = ret.s[3][3] = 1;for (ll i = t*fib[len[t]-1]%K;i != t;(i *= fib[len[i]-1])%=K)cnt += len[i],ret = ret * save[i];cnt += len[t],ret = save[t]*ret;ans = ans*qsm(ret,n/cnt); n %= cnt;sign = true;}}}printf("%lld",(ans.s[1][2]+p)%p);fclose(stdin); fclose(stdout);return 0;
}

转载于:https://www.cnblogs.com/mmlz/p/4298169.html

BZOJ 2432 兔农相关推荐

  1. 【BZOJ 2432】 [Noi2011]兔农 矩乘+数论

    这道题的暴力分还是很良心嘛~~~~~ 直接刚的话我发现本蒟蒻只会暴力,矩乘根本写不出来,然后让我们找一下规律,我们发现如果我们把这个序列在mod k的意义下摆出,并且在此过程中把值为1的的数减一,我们 ...

  2. 写给自己 NOI2012流水帐

    2012.07.25 09:55 飞机在晚点55分钟后终于从成都出发,突然意识到,NOI就这样突兀而自然地开始了. 12:20 终于到达了上海浦东.海风大得惊人.阳光很好.精神不错.好像饿了. 17: ...

  3. NOI2010~NOI2018选做

    [NOI2010] [NOI2010]海拔 高度只需要0/1,所以一个合法方案就是一个割,平面图求最小割. [NOI2010]航空管制 反序拓扑排序,每次取出第一类限制最大的放置,这样做答案不会更劣. ...

  4. [总结]2019年9月 OI学习/刷题记录

    从现在开始记录一下每天的学习情况.主力LOJ? 2019/9/5 LibreOJ #2543. 「JXOI2018」排序问题 答案显然是\(\frac{(n+m)!}{Cnt_1!Cnt_2!\cdo ...

  5. [Luogu P3214] [BZOJ 4339] [HNOI2011]卡农

    洛谷传送门 BZOJ传送门 题目描述 众所周知卡农是一种复调音乐的写作技法,小余在听卡农音乐时灵感大发,发明了一种新的音乐谱写规则.他将声音分成 nnn 个音阶,并将音乐分成若干个片段.音乐的每个片段 ...

  6. bzoj 2437: [Noi2011]兔兔与蛋蛋

    Description Solution 考虑犯错误的条件:之前是处于必胜状态,该操作之后就变成了必败状态. 我们可以把这个过程看成两人对网格图进行黑白染色,变成了一个二分图模型,即当前位置向相邻不同 ...

  7. S-T平面图中利用最短路求最小割(BZOJ 1001)

    BZOJ 1001: [BeiJing2006]狼抓兔子 最小割 题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1001 现在小朋友们最喜欢 ...

  8. Zoom 袁征码农逆袭:8 次申请美国签证被拒,独闯硅谷成亿万富翁

    作者 | 哈那 出品 | 出海瞭望(ID:Globalinsights) Zoom,袁征(Eric S. Yuan). 这可能是你最近在中外科技.财经类报道里经常看到的关键词.继去年成功在纳斯达克上市 ...

  9. BZOJ 1500 Luogu P2042 [NOI2005] 维护数列 (Splay)

    BZOJ 1500 Luogu P2042 [NOI2005] 维护数列 (Splay) 手动博客搬家: 本文发表于20180825 00:34:49, 原地址https://blog.csdn.ne ...

  10. 陶陶的兔二,建好啦!

    今天是2014年12月09日,下午17:07:27,在中油瑞飞成都分公司办公区的工位里,写下了此博客第一篇随笔. 首先,要感谢一直陪伴兔二的陶陶,她是一位美丽善良.默契暖心.温柔聪明.机敏伶俐的女孩儿 ...

最新文章

  1. 计算机二级申请创新学分理由,创新学分申请书范文
  2. mysql 字符转数组_mysql下将分隔字符串转换为数组
  3. Populating Next Right Pointers in Each Node I or II
  4. python实现决策树ID3算法
  5. 老生常谈exec函数族
  6. 为金蝶K3页面增加批量导入选项(其它出库、其它入库、调拨单、生产领料、外购入库、成本调整)
  7. js实现手机横竖屏事件
  8. FPGA 视频处理 FIFO 的典型应用
  9. 尽一下地主之宜,献上关于龙井茶的知识(介绍+分类+购买)
  10. Android 9的神经网络API
  11. git pull 拉取代码的时候报错 Pulling is not possible because you have unmerged files.
  12. Ariane和riscv-gnu-toolchain工具链的安装
  13. git branch分支创建、切换、合并,git tag标签
  14. android电视分辨率是多少合适,电视分辨率多少合适
  15. JavaScript从初级往高级走系列————prototype
  16. 弘辽科技:如何提高客单价
  17. 超高清晰电影寻觅及下载技巧汇集
  18. 1.了解NVIDIA显卡架构
  19. 文件加载时报错:ValueError
  20. 2015年第一季度总结

热门文章

  1. Glide Golang包管理
  2. Python实现图像信息隐藏
  3. python基础之列表、元组和字典
  4. 《网络攻防》第十周学习总结
  5. 编写有效用例_阅读笔记03
  6. 使用CMD实现批量重命名[转]
  7. 提高网页打开速度的一些小技巧
  8. servlet无法自动在web.xml中配置
  9. 陈桂林个人博客传送门
  10. ClientScript.RegisterStartupScript 不起作用