欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - BZOJ3286


题意概括

n,m,a,b,c,d,e,f<=10^1000000


题解

  神奇的卡常题目。

  在此感谢"zhouzixuan"——bzoj 3286: Fibonacci矩阵

  学习他,才15秒卡过此题。

  这题的做法应该很明显的,学过矩阵快速幂的大概几眼就看出来了。

  对于每一行的转移,是相同的,所以矩阵快速幂可以搞定行与行之间的转移。

  然后对于某一行,其实大部分的转移是和abc有关的,同理也可用矩阵快速幂搞定。

  但是如果折半的话,矩阵快速幂的复杂度为log2(n)*len(n)   (高精度运算复杂度)

  要TLE。

  然后我们发现,如果10位10位走,就不用跑高精度了。那么时间复杂度理论上就可以过去了。

  但是这题神坑。

  卡常!!!!!!!

  那么,我们研究矩阵,发现,我们构造的矩阵,有一列(或者一行)的3个数的值总是不变的。

  那么,我们可以减少循环??

  然后,去掉循环,手写9个运算式又可以省去循环变量的几个运算的复杂度。

  然后,仍然不够。我们发现数组访问有点慢,那么我们把数组去掉,改成一个一个的变量。

  这样大概可以快上4倍。

  然后,我们发现之前的那3个不变的也没用了,直接不运算了,其余的按照原先的运算,其中涉及之前的那3个的就把变量名改成值就可以了。

  然后发现还是TLE了。

  您千万不要气馁。

  对于矩阵快速幂中,我原先的版本是这样的:

Mat MatPow(Mat x,int *v,int len){
Mat ans(1),xx;
for (int i=1;i<=len;i++){
for (int j=v[i];j--;)
ans=ans*x;
xx=x=x*x,x=x*x,x=x*x,x=x*xx;
}
return ans;
}

  其实,这个时候,我们不仅要在x上面花时间,又要在ans上花时间,所以,我们要想办法卡。

  事实上,我们可以这样:(省掉了约1/3的时间)

  

inline Mat MatPow(Mat x,int *v,int len){
Mat ans(1),xx;
Mat fac[10];
fac[0].set(1);
for (int i=1;i<=9;i++)
fac[i]=fac[i-1]*x;
for (int i=len;i>=1;i--)
ans=MatPow(ans)*fac[v[i]];
return ans;
}

  

  然后我就过去了。(心)累死了。


update 2017-12-22

在写BZOJ3240的时候,突然发现我当初在写最后的MatPow的时候,有重复计算。然后舍去了重复计算,卡掉了1/3的常数,现在是10秒了。


代码

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
typedef long long LL;
const int mod=2012182013;
struct BigInt{
static const int MaxL=1000005;
int v[MaxL],len;
inline bool isd(char ch){return '0'<=ch&&ch<='9';}
inline void read(){
len=0;
char ch=getchar();
while (!isd(ch))
ch=getchar();
while (isd(ch))
v[++len]=ch-48,ch=getchar();
for (int i=1;i<=len/2;i++)
swap(v[i],v[len+1-i]);
}
inline void minus(){
v[1]--;
for (int i=1;i<len;i++)
if (v[i]<0)
v[i]+=10,v[i+1]--;
else
break;
while (len&&!v[len])
len--;
}
};
inline bool isd(char ch){return '0'<=ch&&ch<='9';}
inline LL getMODed(){
char ch=getchar();
while (!isd(ch))
ch=getchar();
LL res=0;
while (isd(ch))
res=(res*10+ch-48)%mod,ch=getchar();
return res;
}
struct Mat{
LL v11,v12,v21,v22,v31,v32;
inline Mat (){}
inline Mat (int x){(*this).set(x);}
inline void set(int x){
v11=v12=v21=v22=v31=v32=0;
if (x==1)
v11=v22=1;
}
inline void build(int a,int b,int c){
v11=0,v12=a;
v21=1,v22=b;
v31=0,v32=c;
}
inline Mat operator * (Mat &b){
Mat ans;
ans.v11=(v11*b.v11+v12*b.v21)%mod;
ans.v12=(v11*b.v12+v12*b.v22)%mod;
ans.v21=(v21*b.v11+v22*b.v21)%mod;
ans.v22=(v21*b.v12+v22*b.v22)%mod;
ans.v31=(v31*b.v11+v32*b.v21+b.v31)%mod;
ans.v32=(v31*b.v12+v32*b.v22+b.v32)%mod;
return ans;
}
};
inline Mat MatPow(Mat x){
Mat ans(1);
for (int y=10;y;y>>=1,x=x*x)
if (y&1)
ans=ans*x;
return ans;
}
inline Mat MatPow(Mat x,int *v,int len){
Mat ans(1),xx;
Mat fac[10];
fac[0].set(1);
for (int i=1;i<=9;i++)
fac[i]=fac[i-1]*x;
for (int i=len;i>=1;i--)
ans=MatPow(ans)*fac[v[i]];
return ans;
}
LL a,b,c,d,e,f;
BigInt n,m;
Mat Mx,My,en,res;
int main(){
n.read(),m.read();
a=getMODed(),b=getMODed(),c=getMODed();
d=getMODed(),e=getMODed(),f=getMODed();
Mx.build(a,b,c),My.build(d,e,f);
m.minus(),m.minus(),n.minus();
res=MatPow(Mx,m.v,m.len);
en=MatPow(res*My*My,n.v,n.len)*res;
printf("%lld",(en.v12+en.v22+en.v32)%mod);
return 0;
}

  

BZOJ3286 Fibonacci矩阵 矩阵 快速幂 卡常的更多相关文章

  1. BZOJ3240 [Noi2013]矩阵游戏 矩阵 快速幂 卡常

    原文链接http://www.cnblogs.com/zhouzhendong/p/8084891.html 题目传送门 - BZOJ3240 题意概括 F[1][1]=1F[i,j]=a*F[i][ ...

  2. Luogu 1349 广义斐波那契数列(递推,矩阵,快速幂)

    Luogu 1349 广义斐波那契数列(递推,矩阵,快速幂) Description 广义的斐波那契数列是指形如\[A_n=p*a_{n-1}+q*a_{n-2}\]的数列.今给定数列的两系数p和q, ...

  3. 洛谷 P4910 帕秋莉的手环 矩阵乘法+快速幂详解

    矩阵快速幂解法: 这是一个类似斐波那契数列的矩乘快速幂,所以推荐大家先做一下下列题目:(会了,差不多就是多倍经验题了) 注:如果你不会矩阵乘法,可以了解一下P3390的题解 P1939 [模板]矩阵加 ...

  4. Qbxt 模拟赛 Day4 T2 gcd(矩阵乘法快速幂)

    /* 矩阵乘法+快速幂. 一开始迷之题意.. 这个gcd有个规律. a b b c=a*x+b(x为常数). 然后要使b+c最小的话. 那x就等于1咯. 那么问题转化为求 a b b a+b 就是斐波 ...

  5. 矩阵乘法快速幂 codevs 1732 Fibonacci数列 2

    1732 Fibonacci数列 2  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题解  查看运行结果     题目描述 Description 在“ ...

  6. [codevs]1250斐波那契数列<矩阵乘法&快速幂>

    题目描述 Description 定义:f0=f1=1, fn=fn-1+fn-2(n>=2).{fi}称为Fibonacci数列. 输入n,求fn mod q.其中1<=q<=30 ...

  7. 【BZOJ-1009】GT考试 KMP+DP+矩阵乘法+快速幂

    1009: [HNOI2008]GT考试 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 2745  Solved: 1694[Submit][Statu ...

  8. 矩阵乘法快速幂 codevs 1574 广义斐波那契数列

    codevs 1574 广义斐波那契数列  时间限制: 1 s  空间限制: 256000 KB  题目等级 : 钻石 Diamond   题目描述 Description 广义的斐波那契数列是指形如 ...

  9. BZOJ-1875 HH去散步 DP+矩阵乘法快速幂

    1875: [SDOI2009]HH去散步 Time Limit: 20 Sec Memory Limit: 64 MB Submit: 1196 Solved: 553 [Submit][Statu ...

随机推荐

  1. WinCE平台的程序编译到Win32平台下运行

    最近做的项目中,有一个在WinCE平台上跑的程序,后来随着项目的发展,要求此程序在PC上也能跑.感谢VS 2005提供的多平台支持,只需要几分钟就可以解决这个问题,方法很简单,下面是我处理的过程. 1 ...

  2. java结合testng,利用txt做数据源的数据驱动实例

    import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.io.Buffe ...

  3. ELK Packetbeat 部署指南

    http://www.ttlsa.com/elk/elk-packetbeat-deployment-guide/

  4. Confluence 6 用户目录图例 - Confluence 内部目录

    上面的图:Confluence 使用内部目录为用户管理. https://www.cwiki.us/display/CONFLUENCEWIKI/Diagrams+of+Possible+Config ...

  5. bat命令行实现全盘遍历搜索文件

    背景:当想要查找一个文件时,记得放在某个盘里.手动去遍历时感觉好心累,找了半天还是没有找着(虽然win有自带的搜索框,但是看着进度条的速度,我便果断的点了取消).基于这个情况,所以写了脚本满足自身查找 ...

  6. mongodb基类封装实例

    mongodb的基类 1 <?php 2 3 namespace BI\Service\MongoDB; 4 5 use MongoDB\Driver\BulkWrite; 6 use Mong ...

  7. python并发编程之多线程2------------死锁与递归锁,信号量等

    一.死锁现象与递归锁 进程也是有死锁的 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用, 它们都将无法推进下去.此时称系统处于死锁状态或系统 ...

  8. CentOS 7 安装 Redis

    1.Redis 下载地址:https://redis.io/download 2.上传到服务器指定文件夹 ,我这边传到了根目录下 /mysoft 这个目录下 解压  tar  -zxvf redis- ...

  9. java 命令行运行时报错:找不到或无法加载主类

    源码如下: 路径目录(...\src\object) //: ch1.10/Command.java /**@author feilong * @version 1.0 */ package obje ...

  10. Laravel5使用QQ邮箱发送邮件配置

    在.env文件中设置如下MAIL_DRIVER=smtpMAIL_HOST=smtp.qq.comMAIL_PORT=465MAIL_USERNAME=00000000000@qq.comMAIL_P ...