[BZOJ2432][Noi2011]兔农 矩阵乘法+exgcd
2432: [Noi2011]兔农
Time Limit: 10 Sec Memory Limit: 256 MB
Description
农夫栋栋近年收入不景气,正在他发愁如何能多赚点钱时,他听到隔壁的小朋友在讨论兔子繁殖的问题。
问题是这样的:第一个月初有一对刚出生的小兔子,经过两个月长大后,这对兔子从第三个月开始,每个月初生一对小兔子。新出生的小兔子生长两个月后又能每个月生出一对小兔子。问第n个月有多少只兔子?
聪明的你可能已经发现,第n个月的兔子数正好是第n个Fibonacci(斐波那契)数。栋栋不懂什么是Fibonacci数,但他也发现了规律:第i+2个月的兔子数等于第i个月的兔子数加上第i+1个月的兔子数。前几个月的兔子数依次为:
1 1 2 3 5 8 13 21 34 …
栋栋发现越到后面兔子数增长的越快,期待养兔子一定能赚大钱,于是栋栋在第一个月初买了一对小兔子开始饲养。
每天,栋栋都要给兔子们喂食,兔子们吃食时非常特别,总是每k对兔子围成一圈,最后剩下的不足k对的围成一圈,由于兔子特别害怕孤独,从第三个月开始,如果吃食时围成某一个圈的只有一对兔子,这对兔子就会很快死掉。
我们假设死去的总是刚出生的兔子,那么每个月的兔子数仍然是可以计算的。例如,当k=7时,前几个月的兔子数依次为:
1 1 2 3 5 7 12 19 31 49 80 …
给定n,你能帮助栋栋计算第n个月他有多少对兔子么?由于答案可能非常大,你只需要告诉栋栋第n个月的兔子对数除p的余数即可。
Input
输入一行,包含三个正整数n, k, p。
Output
输出一行,包含一个整数,表示栋栋第n个月的兔子对数除p的余数。
Sample Input
Sample Output
HINT
1<=N<=10^18
2<=K<=10^6
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,
性质1:我们发现,每段开头必为相同的两数,并且它们恰是上一段的最末一位非0数;由于总共只有k−1种余数,
所以不超过k段就会出现循环(如果有的话),比如上面k=7时的上面的数列,
3, 3, 6, 2, 0,
2, 2, 4, 6, 3, 2, 5, 0,
(1)根据a* f[len] ≡ 1 (mod k),求出f[len]
(2)根据f[len]和vis数组反推出len
(3)由x*f[len-1]得到下一段的开头。
现在我们的问题就变成了如何求vis数组?
然后据说有一个很强的结论:斐波那契数列在模k意义下一定是以0 1 1……为开头的循环,并且循环节长度<=6*k(但也可能很长,比n大),因此不用担心算不完,只需要暴力递推记录每一位%k的f值和vis值即可
还剩下一点就是转移矩阵:在行内使用下面的A矩阵,在行间转移使用B矩阵。答案矩阵一开始长C这样
1 1 0 1 0 0 0 1 1
1 0 0 0 1 0
0 0 1 -1 0 1
A B C
这样,我们的处理过程就是:递推记录vis数组和f数组->建立转移矩阵->计算每一行的转移矩阵->如果出现循环节,用矩阵乘法快速处理->将剩余的转移用A矩阵乘到C中
这样,本题就被我们切掉了……真的是很不错的一道题。具体实现时还有一些小点需要注意。代码见下:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <ctime>
using namespace std;
typedef long long LL;
const int N=;
LL n,k,p,vis[N],f[N*],ni[N],len[N];
bool ext[N];
void exgcd(LL a,LL b,LL&x,LL &y,LL &d)
{
if(b==)d=a,x=,y=;
else exgcd(b,a%b,y,x,d),y-=x*(a/b);
}
inline LL inv(LL a,LL mod)
{
LL d,x,y;exgcd(a,mod,x,y,d);
return d==?(x+mod)%mod:-;
}
struct marx
{
LL m[][];
marx(){}
inline LL *operator [](LL x){return m[x];}
inline void clear(){memset(m,,sizeof(m));}
marx operator * (const marx &b) const
{
marx c;c.clear();
for(int k=;k<=;k++)
for(int i=;i<=;i++)
for(int j=;j<=;j++)
c.m[i][j]=(c.m[i][j]%p+m[i][k]%p*b.m[k][j]%p)%p;
return c;
}
}mat[N],A,B,C,ans;
inline marx poww(marx x,LL len)
{
marx ret;ret.clear();
ret[][]=ret[][]=ret[][]=;
while(len)
{
if(len&)ret=ret*x;
len>>=;x=x*x;
}
return ret;
}
int main()
{
scanf("%lld%lld%lld",&n,&k,&p);
f[]=f[]=;
for(int i=;;i++)
{
f[i]=(f[i-]+f[i-])%k;
if(!vis[f[i]])vis[f[i]]=i;
if(f[i]==f[i-]&&f[i]==)break;
}
A[][]=A[][]=A[][]=A[][]=;
B[][]=B[][]=B[][]=,B[][]=-;
ans[][]=ans[][]=;
LL x=;bool flag=;
while(n)
{
if(!ni[x])ni[x]=inv(x,k);
if(ni[x]==-)ans=ans*poww(A,n),n=;
else
{
if(!ext[x]||flag)
{
ext[x]=;
if(!vis[ni[x]])
ans=ans*poww(A,n),n=;
else
{
len[x]=vis[ni[x]];
if(n>=len[x])
{
n-=len[x];
mat[x]=poww(A,len[x])*B;
ans=ans*mat[x],x=x*f[len[x]-]%k;
}
else ans=ans*poww(A,n),n=;
}
}
else
{
LL cnt=;
C.clear();C[][]=C[][]=C[][]=;
for(LL i=x*f[len[x]-]%k;i!=x;i=i*f[len[i]-]%k)
cnt+=len[i],C=C*mat[i];
cnt+=len[x],C=mat[x]*C;
ans=ans*poww(C,n/cnt);
n%=cnt,flag=;
}
}
}
printf("%lld",(ans[][]%p+p)%p);
}
[BZOJ2432][Noi2011]兔农 矩阵乘法+exgcd的更多相关文章
- BZOJ2432 [Noi2011]兔农
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...
- 2432: [Noi2011]兔农 - BZOJ
Description 农夫栋栋近年收入不景气,正在他发愁如何能多赚点钱时,他听到隔壁的小朋友在讨论兔子繁殖的问题. 问题是这样的:第一个月初有一对刚出生的小兔子,经过两个月长大后,这对兔子从第三个月 ...
- 【BZOJ 2432】 [Noi2011]兔农 矩乘+数论
这道题的暴力分还是很良心嘛~~~~~ 直接刚的话我发现本蒟蒻只会暴力,矩乘根本写不出来,然后让我们找一下规律,我们发现如果我们把这个序列在mod k的意义下摆出,并且在此过程中把值为1的的数减一,我们 ...
- NOI2011 兔农
http://www.lydsy.com/JudgeOnline/problem.php?id=2432 感觉是day1中最难的一题,还好出题人很良心,给了75分部分分. 还是跪拜策爷吧~Orz ht ...
- 【BZOJ2432】【NOI2011】兔农(数论,矩阵快速幂)
[BZOJ2432][NOI2011]兔农(数论,矩阵快速幂) 题面 BZOJ 题解 这题\(75\)分就是送的,我什么都不想写. 先手玩一下,发现每次每次出现\(mod\ K=1\)的数之后 把它减 ...
- Codeforces 1106F Lunar New Year and a Recursive Sequence | BSGS/exgcd/矩阵乘法
我诈尸啦! 高三退役选手好不容易抛弃天利和金考卷打场CF,结果打得和shi一样--还因为queue太长而unrated了!一个学期不敲代码实在是忘干净了-- 没分该没分,考题还是要订正的 =v= 欢迎 ...
- [bzoj2432]兔农
将每一个重置为0的点作为一段,那么它会导致后面为以x x为开头的斐波拿起数列的东西,那么设这一段是以x为开头,要快速转移到下一段,就可以解决这道题目为了转移,我们要处理出下面的东西:1.求出x关于模k ...
- BZOJ 2432 兔农
Description 农夫栋栋近年收入不景气,正在他发愁如何能多赚点钱时,他听到隔壁的小朋友在讨论兔子繁殖的问题. 问题是这样的:第一个月初有一对刚出生的小兔子,经过两个月长大后,这对兔子从第三个月 ...
- *HDU2254 矩阵乘法
奥运 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submissi ...
随机推荐
- 【转载】TCP/IP 之 大明王朝邮差
原文:TCP/IP 之 大明王朝邮差 原创 2016-05-12 刘欣 码农翻身 前言: 本文主要想说一下TCP的知识, 比喻有不恰当之处,敬请包涵. 大明王朝天启四年, 清晨. 天色刚蒙蒙亮,我就赶 ...
- Drupal7 实现like(点赞)功能
尝试了好几个模块做下总结: 1. Like Dislike Buttons 好处:代码实现简单,一看就懂,开启后无需任何配置,自动在node底部显示like和unlike的小手.而且模版改起来也容易. ...
- maven 手动安装jar包
1.问题 maven有时候在pom文件引入jar包会报错,所以可以通过手动导入jar包的方式导入. 2.解决: 通过maven命令导入jar包, mvn install:install-file -D ...
- PHP:Iterator(迭代器)接口和生成器
迭代器 可在内部迭代自己的外部迭代器或类的接口.详情:http://php.net/manual/zh/class.iterator.php 接口摘要 Iterator extends Travers ...
- oracle的分号和斜杠/
;是执行语句必须的/是执行语句块必须的 比如执行一个触发器 CREATE OR REPLACE TRIGGER "TRG_1" BEFORE INSERT ON "CAT ...
- 自动化运维工具saltstack01 -- 之SaltStack介绍、安装与基础使用
SaltStack介绍 官网地址:http://www.saltstack.com 官方文档地址:http://docs.saltstack.com Github:http://Github.com/ ...
- 2018 ACM-ICPC World Finals - Beijing F.Go with the Flow
先枚举所有的列长度 对于每种列长度,然后里面用dp算 #include <algorithm> #include <cmath> #include <cstdio> ...
- Unity ScriptableObject自定义属性显示
1. 继承Editor,重写OnInspectorGUI方法 Editor官方文档 需求 将TestClass中intData属性和stringData按指定格式显示. 实现 定义一个测试类TestC ...
- PaaSoo云通讯-印度市场机遇与挑战并存
2019年4月16日,由白鲸出海举办的2019中印互联网大会(Global Connects India)在印度新德里举行,这次的大会主要涵盖了出海主题峰会.B2B展会.中印互联网高层圆桌等模块. 众 ...
- linux下各文件夹的结构说明及用途介绍(转载)
详细介绍文档 转载文章路径 /bin:二进制可执行命令. /dev:设备特殊文件. /etc:系统管理和配置文件. /etc/rc.d:启动的配 置文件和脚本. /home:用户主目录的基点,比如用户 ...