BZOJ3286 Fibonacci矩阵 矩阵 快速幂 卡常
欢迎访问~原文出处——博客园-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矩阵 矩阵 快速幂 卡常的更多相关文章
- BZOJ3240 [Noi2013]矩阵游戏 矩阵 快速幂 卡常
原文链接http://www.cnblogs.com/zhouzhendong/p/8084891.html 题目传送门 - BZOJ3240 题意概括 F[1][1]=1F[i,j]=a*F[i][ ...
- Luogu 1349 广义斐波那契数列(递推,矩阵,快速幂)
Luogu 1349 广义斐波那契数列(递推,矩阵,快速幂) Description 广义的斐波那契数列是指形如\[A_n=p*a_{n-1}+q*a_{n-2}\]的数列.今给定数列的两系数p和q, ...
- 洛谷 P4910 帕秋莉的手环 矩阵乘法+快速幂详解
矩阵快速幂解法: 这是一个类似斐波那契数列的矩乘快速幂,所以推荐大家先做一下下列题目:(会了,差不多就是多倍经验题了) 注:如果你不会矩阵乘法,可以了解一下P3390的题解 P1939 [模板]矩阵加 ...
- Qbxt 模拟赛 Day4 T2 gcd(矩阵乘法快速幂)
/* 矩阵乘法+快速幂. 一开始迷之题意.. 这个gcd有个规律. a b b c=a*x+b(x为常数). 然后要使b+c最小的话. 那x就等于1咯. 那么问题转化为求 a b b a+b 就是斐波 ...
- 矩阵乘法快速幂 codevs 1732 Fibonacci数列 2
1732 Fibonacci数列 2 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Description 在“ ...
- [codevs]1250斐波那契数列<矩阵乘法&快速幂>
题目描述 Description 定义:f0=f1=1, fn=fn-1+fn-2(n>=2).{fi}称为Fibonacci数列. 输入n,求fn mod q.其中1<=q<=30 ...
- 【BZOJ-1009】GT考试 KMP+DP+矩阵乘法+快速幂
1009: [HNOI2008]GT考试 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 2745 Solved: 1694[Submit][Statu ...
- 矩阵乘法快速幂 codevs 1574 广义斐波那契数列
codevs 1574 广义斐波那契数列 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 广义的斐波那契数列是指形如 ...
- BZOJ-1875 HH去散步 DP+矩阵乘法快速幂
1875: [SDOI2009]HH去散步 Time Limit: 20 Sec Memory Limit: 64 MB Submit: 1196 Solved: 553 [Submit][Statu ...
随机推荐
- Struts2配置拦截器
<package name="loginaction" namespace="/" extends="struts-default"& ...
- 任意N位二进制的补码实现——队列存放
正在学习计算机组织与结构,为了写一些底层的算术操作模拟,比如一个二进制补码数的加减乘除,发现这很麻烦,因为不管是什么语言,都只提供了8位.32.64位等部分位数的补码形式,那么怎么实现任意任意位的补码 ...
- 【进阶2-3期】JavaScript深入之闭包面试题解
这是我在公众号(高级前端进阶)看到的文章,现在做笔记 https://github.com/yygmind/blog/issues/19 作用域指的是一个变量和函数的作用范围,JS中函数内声明的所有变 ...
- 信息摘要算法之五:HMAC算法分析与实现
MAC(Message Authentication Code,消息认证码算法)是含有密钥散列函数算法,兼容了MD和SHA算法的特性,并在此基础上加上了密钥.因此MAC算法也经常被称作HMAC算法. ...
- Eclipse 软件 Java 解决:出现的editor does not contain a main type错误框 问题
Eclipse 软件 解决:出现的 editor does not contain a main type 错误框 问题 当你运行 Java文件是,如果弹出了下面的 错误框: 出现错误的原因: 当前的 ...
- 设置 Confluence 6 日志
Confluence 使用的是 Apache's log4j 日志服务.能够允许管理员通过编辑配置文件来控制日志的表现和日志输出文件.在系统中有 6 个日志输出级别,请参考 log4j logging ...
- Confluence 6 手动安装语言包和找到更多语言包
手动安装语言包 希望以手动的方式按照语言包,你需要按照下面描述的方式上传语言包.一旦你安装成功后,语言包插件将会默认启用. 插件通常以 JAR 或者 OBR(OSGi Bundle Repositor ...
- js之DOM对象一
一.什么是HTML DOM HTML Document Object Model(文档对象模型) HTML DOM 定义了访问和操作HTML文档的标准方法 HTML DOM 把 HTML 文档呈现 ...
- WireShark Wifi认证数据包分析(论文idea)
1.使用 wireShark捕获802.11数据帧结构分成三种,管理帧.控制帧.数据帧. 使用的过滤语法: 过滤MAC 地址: Waln.bssid eq=8c:23:0c:44:21:0f 过滤特定 ...
- Android手机流量分析工具介绍
一.20 Best Android Hacking Apps And Tools Of 2018 首先罗列常见的Android手机hacking的工具 #1The Android Network Ha ...