欢迎访问~原文出处——博客园-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. HDU 1077

    题意 : 给你 N 个点, 问一个单位圆最大能包括几个点 直接暴力枚举圆心, 计算个数        O(n^ 3): 精度,细节都要注意, //#include<bit/stdc++.h> ...

  2. JetBrains GoLand 2018 激活码/ 注册码(最新破解方法)

    1 前言 本机测试环境如下: Goland版本:2018.1.5 电脑系统:win7 64位 JetbrainsCrack.jar:链接: https://pan.baidu.com/s/1blmN3 ...

  3. [转]TSVNCache.exe卡死电脑的解决方法

    转至于https://blog.csdn.net/gnail_oug/article/details/55506820. 正文如下: 每当打开explorer资源管理器的时候,经常卡死,换了固态硬盘还 ...

  4. CLOB数据类型截取SUBSTR_按开始位置偏移量

    --DBMS_LOB.substr不加参数表示全部截取,负向截取待定 CREATE OR REPLACE FUNCTION CLOB_SUBSTR( V_CLOB CLOB, N_OFFSET NUM ...

  5. LuoGu P1006 传纸条

    题目传送门 这题嘛...方格取数和这题一样一样的 只不过这题是从左上到右下再回去罢了(来回一趟和来两趟有区别么?没有,那么这题和上题用一样的转移和状态就行了 没什么好说的,说一下我的错误好了: 人家图 ...

  6. swift 学习- 17 -- 析构器

    // 析构器 只适用与 类类型, 当一个类的实例被释放之前, 析构器会被立即调用, 析构器用关键字 deinit 来标示, 类似于构造器要用 init 来标示 // 析构过程原理 // Swift 会 ...

  7. Confluence 6 为外部用户管理获得支持

    本页面描述了如果你在配置外部用户管理的时候遇到了问题,如何向 Atlassian 支持项目组寻求帮助.外部用户目录挂你包括 Active Directory,其他 LDAP 服务器,Atlassian ...

  8. Java编程的分期步骤(一)

    日期:2018.8.12 星期一 博客期:005 不知不觉来到第五期了,先简单说一下Java环境!(虽然Java都自学完了才说....)首先,就是在网站上下载一个java包,之后把它下载到全英文的一个 ...

  9. bzoj2973转移矩阵构造法!

    /* 构造单位矩阵(转移矩阵) 给定n*m网格,每个格子独立按照长度不超过6的操作串循环操作 对应的操作有 0-9:拿x个石头到这个格子 nwse:把这个格子的石头推移到相邻格子 d:清空该格石子 开 ...

  10. Python算法之二分查找法

    1: l = [2,3,5,10,15,16,18,22,26,30,32,35,41,42,43,55,56,66,67,69,72,76,82,83,88] 从列表中找到某个num的位置 def ...