这道题的暴力分还是很良心嘛~~~~~

直接刚的话我发现本蒟蒻只会暴力,矩乘根本写不出来,然后让我们找一下规律,我们发现如果我们把这个序列在mod k的意义下摆出,并且在此过程中把值为1的的数减一,我们发现他可以成为一段一段的被0(我们在此只关注减1变为0的点)区间,我们继续分析我们分析出来了这样的性质:如果存在这样的点,那么他右边的点一定是两个重复的数,而且往后是fibonacci数列(重头开始)乘第一个数,那么他之后再出现这样的0,的充要条件是其后存在一个fibonacci数是这段数第一个数的逆元。

我们先介绍一个结论(本蒟蒻并不会证):斐波那契数列模k后一定是0,1,1开头的纯循环,而且这个循环节的长度≤6k。我们开一个数组vis[i]表示第一个在mod k意义下值为i的fibonacci数的位置,这样我们求出某个数的逆元就知道以这个数为首项的数段的长度了(这样我们就可以跳啦)。

现在我说一下到了现在我们做了什么,我们发现在mod k 的意义下,这个数列会是一个由0(再次强调我们在此只关注减1变为0的点)隔开散区间(一整个也算)开头,之后要么成为循环,要么不再有0。先解释成为循环:因为我们在mod k的意义下因此最多不过k个数段就可以找到循环。我们再解释一下不在有0,这个就是当这个数段的第一项在mod k的意义下没有逆元,或者有逆元但是找不到vis[]。

现在我们用k再乘一个不大的数的时间复杂度找出来我们要处理的假fibonacci在哪些位置减一,以及他到底是存在循环节还是到后来没有了0,现在我们就可以想到一些矩阵,进行操作,但是这些矩阵一定要满足可乘。对于循环节我们暴力处理两边和一个循环节,对于最后没有0,我们就在后面直接fibonacci。

坑:I.via[1]!=1!!!!我们要找的是他后面第一个1,而我们前两个数是受法律保护的。

  II.对于处理一段一段的,最后一段可能顶到n,不满

  |||.一定要注意矩阵乘没有交换律

#include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long LL;
const LL N=;
LL n,k,p,vis[N],f[N*],Ola,Stop,L,R,pos[N];
LL a[][],b[][],temp_ab[][],F[],temp_F[],S[][];
bool huzhi[N];
LL GCD(LL x,LL y){
return x==?y:GCD(y%x,x);
}
inline LL Min(LL x,LL y){
return x<y?x:y;
}
inline void get_Ola(){
LL lim=(LL)sqrt(k+0.5);
LL x=k;Ola=k;
for(LL i=;i<=lim;i++)
if(x%i==){
Ola=Ola/i*(i-);
while(x%i==)x/=i;
}
if(x!=){
Ola=Ola/x*(x-);
}
}
//*******************GCD&&Ola*********************//
inline void Multi_One(){
memset(temp_F,,sizeof(temp_F));
for(int i=;i<=;i++)
for(int j=;j<=;j++)
temp_F[i]=(temp_F[i]+F[j]*a[j][i]%p+p)%p;
memcpy(F,temp_F,sizeof(F));
}
inline void Multi_Two(){
memset(temp_ab,,sizeof(temp_ab));
for(int i=;i<=;i++)
for(int j=;j<=;j++)
for(int l=;l<=;l++)
temp_ab[i][j]=(temp_ab[i][j]+a[i][l]*a[l][j]%p+p)%p;
memcpy(a,temp_ab,sizeof(a));
}
inline void Multi_Three(){
memset(temp_F,,sizeof(temp_F));
for(int i=;i<=;i++)
for(int j=;j<=;j++)
temp_F[i]=((temp_F[i]+F[j]*b[j][i]%p)%p+p)%p;
memcpy(F,temp_F,sizeof(F));
}
inline void Multi_Four(){
memset(temp_ab,,sizeof(temp_ab));
for(int i=;i<=;i++)
for(int j=;j<=;j++)
for(int l=;l<=;l++)
temp_ab[i][j]=(temp_ab[i][j]+S[i][l]*a[l][j]%p+p)%p;
memcpy(S,temp_ab,sizeof(S));
}
inline void Multi_Five(){
memset(temp_ab,,sizeof(temp_ab));
for(int i=;i<=;i++)
for(int j=;j<=;j++)
for(int l=;l<=;l++)
temp_ab[i][j]=(temp_ab[i][j]+a[i][l]*a[l][j]%p)%p;
memcpy(a,temp_ab,sizeof(a));
}
inline void Multi_Six(){
memset(temp_ab,,sizeof(temp_ab));
for(int i=;i<=;i++)
for(int j=;j<=;j++)
for(int l=;l<=;l++)
temp_ab[i][j]=(temp_ab[i][j]+S[i][l]*b[l][j]%p+p)%p;
memcpy(S,temp_ab,sizeof(S));
}
inline void Multi_Seven(){
memset(temp_F,,sizeof(temp_F));
for(int i=;i<=;i++)
for(int j=;j<=;j++)
temp_F[i]=(temp_F[i]+F[j]*S[j][i]%p+p)%p;
memcpy(F,temp_F,sizeof(F));
}
inline void Multi_E(){
memset(temp_ab,,sizeof(temp_ab));
for(int i=;i<=;i++)
for(int j=;j<=;j++)
for(int l=;l<=;l++)
temp_ab[i][j]=(temp_ab[i][j]+S[i][l]*S[l][j]%p+p)%p;
memcpy(S,temp_ab,sizeof(S));
}
//*********************Multi**********************//
inline LL Pow(LL x,LL y,LL P){
LL ans=;
while(y){
if(y&)ans=ans*x%P;
y>>=,x=x*x%P;
}
return ans;
}
inline void POW(int step){
while(step){
if(step&)Multi_Seven();
step>>=,Multi_E();
}
}
//**********************POW***********************//
inline void Stop_Forever(){
LL now=,step=;
while(){
if(step>=n){
Stop=n;
break;
}
if(pos[now]){
L=pos[now],R=step-;
break;
}
pos[now]=step;
if(huzhi[now]==){
Stop=step-;break;
}
LL Now=Pow(now,Ola-,k);
if(vis[Now]==){
Stop=step-;break;
}
step+=vis[Now];
now=f[vis[Now]-]*now%k;
}
}
//*********************Judge*********************//
inline void F_H(){
f[]=,f[]=;
for(int i=;i<=*k;i++)
f[i]=(f[i-]+f[i-])%k,vis[f[i]]=vis[f[i]]==?i:vis[f[i]];
for(int i=;i<k;i++)
if(GCD(i,k)==)huzhi[i]=;
}
inline void Pre(){
b[][]=;
b[][]=;
b[][]=-,b[][]=;
F[]=,F[]=F[]=;
}
inline void Init(){
scanf("%lld%lld%lld",&n,&k,&p);
F_H();
get_Ola();
Stop_Forever();
Pre();
}
//***********************Pre**********************//
inline void GO(LL step){
memset(a,,sizeof(a));
a[][]=;
a[][]=,a[][]=;
a[][]=;
while(step){
if(step&)Multi_One();
step>>=,Multi_Two();
}
}
inline void GO_ON(int step){
memset(a,,sizeof(a));
a[][]=;
a[][]=,a[][]=;
a[][]=;
while(step){
if(step&)Multi_Four();
step>>=,Multi_Five();
}
}
inline void Get_Boss(LL &now,LL &step){
S[][]=;
S[][]=;
S[][]=;
while(step<R){
LL Now=Pow(now,Ola-,k);
LL y=vis[Now];
if(!step)y--;
GO_ON(y);
if(!step)y++;
step+=y;
Multi_Six();
now=f[vis[Now]-]*now%k;
}
}
//****************Carry On******************//
inline void Work_Stop(){
LL now=,step=;
while(step<Stop){
LL Now=Pow(now,Ola-,k);
LL y=Min(n-step,vis[Now]);
if(!step)y--;
GO(y);
if(!step)y++;
step+=y;
if(y==vis[Now])Multi_Three();
now=f[vis[Now]-]*now%k;
}
GO(n-step);
printf("%lld",F[]);
}
inline void Work_Forever(){
LL now=,step=;
while(step<L-){
LL Now=Pow(now,Ola-,k);
LL y=vis[Now];
if(!step)y--;
GO(y);
if(!step)y++;
step+=y;
Multi_Three();
now=f[vis[Now]-]*now%k;
}
Get_Boss(now,step);
POW((n-L+)/(R-L+));
step=(n-L+)/(R-L+)*(R-L+)+L-;
while(step<n){
LL Now=Pow(now,Ola-,k);
LL y=Min(n-step,vis[Now]);
GO(y);
step+=y;
if(y==vis[Now])Multi_Three();
now=f[vis[Now]-]*now%k;
}
printf("%lld",F[]);
}
//*********************War*****************//
int main(){
Init();
if(Stop)Work_Stop();
else Work_Forever();
return ;
}

【BZOJ 2432】 [Noi2011]兔农 矩乘+数论的更多相关文章

  1. 2432: [Noi2011]兔农 - BZOJ

    Description 农夫栋栋近年收入不景气,正在他发愁如何能多赚点钱时,他听到隔壁的小朋友在讨论兔子繁殖的问题. 问题是这样的:第一个月初有一对刚出生的小兔子,经过两个月长大后,这对兔子从第三个月 ...

  2. [BZOJ2432][Noi2011]兔农 矩阵乘法+exgcd

    2432: [Noi2011]兔农 Time Limit: 10 Sec  Memory Limit: 256 MB Description 农夫栋栋近年收入不景气,正在他发愁如何能多赚点钱时,他听到 ...

  3. bzoj 2437[Noi2011]兔兔与蛋蛋 黑白染色二分图+博弈+匈牙利新姿势

    noi2011 兔兔与蛋蛋 题目大意 直接看原题吧 就是\(n*m\)的格子上有一些白棋和一些黑棋和唯一一个空格 兔兔先手,蛋蛋后手 兔兔要把与空格相邻的其中一个白棋移到空格里 蛋蛋要把与空格相邻的其 ...

  4. BZOJ2432 [Noi2011]兔农

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...

  5. NOI2011 兔农

    http://www.lydsy.com/JudgeOnline/problem.php?id=2432 感觉是day1中最难的一题,还好出题人很良心,给了75分部分分. 还是跪拜策爷吧~Orz ht ...

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

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

  7. BZOJ.2437.[NOI2011]兔兔与蛋蛋游戏(二分图博弈 匈牙利)

    题目链接 首先空格的移动等价于棋子在黑白格交替移动(设起点移向白格就是黑色),且不会走到到起点距离为奇数的黑格.到起点距离为偶数的白格(删掉就行了),且不会重复走一个格子. (然后策略就同上题了,只不 ...

  8. 【BZOJ2432】【NOI2011】兔农(数论,矩阵快速幂)

    [BZOJ2432][NOI2011]兔农(数论,矩阵快速幂) 题面 BZOJ 题解 这题\(75\)分就是送的,我什么都不想写. 先手玩一下,发现每次每次出现\(mod\ K=1\)的数之后 把它减 ...

  9. 【BZOJ 2437】 2437: [Noi2011]兔兔与蛋蛋 (博弈+二分图匹配**)

    未经博主同意不得转载 2437: [Noi2011]兔兔与蛋蛋 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 693  Solved: 442 Des ...

随机推荐

  1. 【Python让生活更美好01】os与shutil模块的常用方法总结

    Python作为一种解释型的高级语言,脚本语言,又被称作“胶水语言”,就是因为其灵活的语法和其依靠浩如烟海的第三方包实现的丰富多彩的功能,而os和shutil就是这样一种功能强大的模块,可以非常快捷地 ...

  2. 41-Individual authentication 模板

    1-创建项目,进入vscode控制台,输出如下命令, uld表示指定mssqllocaldb E:\coding\netcore>dotnet new mvc -au Individual -u ...

  3. C#的委托Delegate

    一.委托基础 1.什么是委托 委托(Delegate) 是存有对某个方法的引用的一种引用类型变量,用关键字delegate申明,实现相同返回值和参数的函数的动态调用,提供了对方法的抽象. 委托(Del ...

  4. LeetCode:12. Roman to Integer (Easy)

    1. 原题链接 https://leetcode.com/problems/roman-to-integer/description/ 2. 题目要求 (1)将罗马数字转换成整数:(2)范围1-399 ...

  5. guacamole实现剪切复制

    主要功能是实现把堡垒机的内容复制到浏览器端,把浏览器端的文本复制到堡垒机上. 借助一个中间的文本框,现将堡垒机内容复制到一个文本框,然后把文本框内容复制出来.或者将需要传递到堡垒机的内容先复制到文本框 ...

  6. howto:在构建基于debian的docker基础镜像时,更换国内包源

    debian经常被用作构建应用镜像的基础镜像,如微软在构建linux下的dotnetcore基础镜像时,提供了基于debian 8(jessie)和debian 9(stretch)的镜像. 由于这些 ...

  7. iOS URL加解密

    URL加解密 背景介绍 iOS 下URL加解密,项目使用AFNetworking 虽然是使用HTTPS,但是从安全方面考虑,在很多情况下还是需要对url的参数进行加密的. 接口如 https://19 ...

  8. (2)分布式下的爬虫Scrapy应该如何做-关于对Scrapy的反思和核心对象的介绍

    本篇主要介绍对于一个爬虫框架的思考和,核心部件的介绍,以及常规的思考方法: 一,猜想 我们说的爬虫,一般至少要包含几个基本要素: 1.请求发送对象(sender,对于request的封装,防止被封) ...

  9. windows中vim以及cmder的使用

    虽然有gvim,但是我依然更喜欢控制台(可理解为博主的偏执已经发展到某个阶段). windows自带的控制台很糟糕,尤其是我正在用的win7竟然没有全屏功能.任何一个占领屏幕的图标显然是不可忍受的. ...

  10. @property, @classmethod基本用法

    @property 废话少说,贴上代码(代码参考@廖雪峰教程) class Student(object): def __init__(self, score): self._score = scor ...