这个题目搞了我差不多一个下午,之前自己推出一个公式,即 f[n+k]=k*f[n]+f[n-1]结果发现根本不能用,无法降低复杂度。

后来又个博客的做法相当叼,就按他的做法来了

即 最终求得是 S(n)=f[b]+f[b+k]+f[b+2*k]....f[b+n*k] (原题的意思好像是不用加到第n项,但实测确实要加到该项)

然后我们令 A={1,1}(标准的斐波那契矩阵)

{1,0}发现 f[b]=A^b,f[b+k]=A^(b+k),....f[b+nk]=A^(b+nk);

提取公共因子 A^b.S(n)=A^b*(E+A^K+A^K^2....A^K^n)

再令K=A^K  (K和E都是矩阵,E为单位矩阵)。于是S(n)=A^b*(E+K+k^2+K^3+...K^n);

这样我们的目的大概出来了,就是要尽可能短的算出 上式括号中的内容(A^b可以用经典斐波那契矩阵很快算出来)

于是构造一个嵌套矩阵

令 SK={K,E},(K,E,0均为矩阵),SK^N={K^N ,  E+K+K^2+K^3+...K^N}

{0,E}                                         {0    ,  E       }

这样只要求出SK^N,取其第一行的第二项 再与 A^b相乘,即可得出最终结果

嵌套矩阵跟普通矩阵差不多,调用写好的矩阵乘法即可实现嵌套矩阵的乘法和乘方

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll __int64
using namespace std;
ll k,b,n,M;
struct Mat
{
ll mat[][];
} Fb,E,zero,A;
struct Smart
{
Mat d[][];
} SK,SE;
void test(Mat t)
{
for (int i=;i<;i++)
{
for (int j=;j<;j++)
cout<<t.mat[i][j]<<" ";
cout<<endl;
}
}
void test2(Smart tmp)
{
for (int i=;i<;i++)
{
for (int j=;j<;j++)
test(tmp.d[i][j]);
}
}
Mat operator +(Mat a,Mat b)
{
Mat c;
for (int i=;i<;i++)
{
for (int j=;j<;j++)
{
c.mat[i][j]=a.mat[i][j]+b.mat[i][j];
c.mat[i][j]%=M;
}
}
return c;
}
Mat operator *(Mat a,Mat b)
{
Mat c;
memset(c.mat,,sizeof c.mat);
for (int i=;i<;i++)
{
for (int j=;j<;j++)
{
for (int k=;k<;k++)
{
c.mat[i][j]+=a.mat[i][k]*b.mat[k][j];
if (c.mat[i][j]>=M)
c.mat[i][j]%=M;
}
}
}
return c;
}
Mat operator ^(Mat a,ll x)
{
//if (x==0) return a;
// cout<<x<<" the x"<<endl;
Mat c=E;
for (;x;x>>=)
{
if (x&)
c=c*a;
a=a*a;
}
return c;
}
Smart operator *(Smart a,Smart b) //大矩阵的乘法 调用普通矩阵的乘法和加法公式即可
{
Smart c;
Mat tmp;
for (int i=;i<;i++)
{
for (int j=;j<;j++)
{
c.d[i][j]=zero;
for (int k=;k<;k++)
{
tmp=a.d[i][k]*b.d[k][j];
c.d[i][j]=c.d[i][j]+tmp;
}
}
}
return c;
}
Smart operator ^(Smart a,ll x) //大矩阵的乘法 调用普通矩阵的乘法公式即可
{
Smart c=SE;
// if (x==0) return a;
//cout<<x<<" the s x "<<endl;
for (;x;x>>=)
{
if (x&)
c=c*a;
a=a*a;
// test2(c);
}
// test2(c);
return c;
}
void init()
{
memset(zero.mat,,sizeof zero);
memset(E.mat,,sizeof E.mat);
for (int i=;i<;i++)
E.mat[i][i]=;
Mat A;
memset(A.mat,,sizeof A.mat); SE.d[][]=SE.d[][]=E;
SE.d[][]=SE.d[][]=zero; A.mat[][]=A.mat[][]=A.mat[][]=;
Fb=A^b;
//test(Fb);
SK.d[][]=A^k;
SK.d[][]=SK.d[][]=E;
SK.d[][]=zero;
}
int main()
{ while (scanf("%I64d %I64d %I64d %I64d",&k,&b,&n,&M)!=EOF)
{
init();
Smart s=SK^n;
Mat tmp=s.d[][];
//test(tmp);
Mat ans=Fb*tmp;
printf("%I64d\n",ans.mat[][]);//因为Fb求出来 真正的 A^b在[1][0]处,但是最终结果为何也是1 0处 我觉得还是有待考究 }
return ;
}

HDU 1588 矩阵快速幂 嵌套矩阵的更多相关文章

  1. Luogu 3390 【模板】矩阵快速幂 (矩阵乘法,快速幂)

    Luogu 3390 [模板]矩阵快速幂 (矩阵乘法,快速幂) Description 给定n*n的矩阵A,求A^k Input 第一行,n,k 第2至n+1行,每行n个数,第i+1行第j个数表示矩阵 ...

  2. 51nod 1113 矩阵快速幂( 矩阵快速幂经典模板 )

    1113 矩阵快速幂 链接:传送门 思路:经典矩阵快速幂,模板题,经典矩阵快速幂模板. /******************************************************* ...

  3. LA 3704 (矩阵快速幂 循环矩阵) Cellular Automaton

    将这n个格子看做一个向量,每次操作都是一次线性组合,即vn+1 = Avn,所求答案为Akv0 A是一个n*n的矩阵,比如当n=5,d=1的时候: 不难发现,A是个循环矩阵,也就是将某一行所有元素统一 ...

  4. hdu6470 矩阵快速幂+构造矩阵

    http://acm.hdu.edu.cn/showproblem.php?pid=6470 题意 \(f[n]=2f[n-2]+f[n-1]+n^3,n \leq 10^{18}\),求f[n] 题 ...

  5. 题解——洛谷P3390 【模板】矩阵快速幂(矩阵乘法)

    模板题 留个档 #include <cstdio> #include <algorithm> #include <cstring> #define int long ...

  6. hdu 1597(矩阵快速幂)

    1597: 薛XX后代的IQ Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 228  Solved: 55[Submit][Status][Web Bo ...

  7. poj4474 Scout YYF I(概率dp+矩阵快速幂)

    Scout YYF I Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4100   Accepted: 1051 Descr ...

  8. hdu3483之二项式展开+矩阵快速幂

    A Very Simple Problem Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Ot ...

  9. Educational Codeforces Round 60 D dp + 矩阵快速幂

    https://codeforces.com/contest/1117/problem/D 题意 有n个特殊宝石(n<=1e18),每个特殊宝石可以分解成m个普通宝石(m<=100),问组 ...

随机推荐

  1. Verilog 2001 `default_nettype none

    在Verilog 1995規定,對於沒宣告的信號會自動視為wire,這樣常常造成debug的困難,Verilog 2001另外定義了`default_nettype none,將不再自動產生wire. ...

  2. makecert 制作数字证书 给DLL加一个数字签名

    声明:文章整理自互联网 我仅需要给dll添加(替换)一个签名,所以我只看了第一步和第三步,其余的部分我没有测试,不能保证内容的是否正确. 看了很多关于DLL加签名的教程 大多是错误的 完全无法正常走下 ...

  3. JAVA笔记01 变量的取名

    第2章 有意义的命名2.1 介绍2.2 名副其实 变量名太随意,haha.list1.ok 这些都没啥意义2.3 避免误导 包含List等关键字.字母o与数字0等2.4 做有意义的区分 反面教材,变量 ...

  4. 如何用naviecat批量创建mysql数据

    1.参考博文:https://blog.csdn.net/lelly52800/article/details/87267096 2.excel要与表结构一致 3.右键,导入向导,选择相应版本,点击“ ...

  5. POJ 2796:Feel Good 单调栈经典题

    Feel Good Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 11626   Accepted: 3212 Case T ...

  6. <强化学习>无模型下计算给定策略对应的价值函数,Model free Prediction,评估一个给定策略的表现

    一.Intro Prediction只是评估给定策略的表现,直白的说它是找 “在环境ENV下,AGENT按照给定的策略pai,AGENT的价值函数”. 这篇blog只介绍三种计算方法,没有涉及到 “求 ...

  7. 面试题(9)之 leetcode-189

    题目描述 解法一: /** * @param {number[]} nums * @param {number} k * @return {void} Do not return anything, ...

  8. ICE使用记录

    在使用ice中间件的过程中 如果A继承了 ****Disp_类 在使用A类的时候 ****Disp_类会浅表克隆该类出一个新的对象a 在调用重写的接口的时候是使用a 在主动调用A类的对象的时候使用的才 ...

  9. springboot - 使用ErrorAttributes 在我们自定义的 ErrorController中

    1.概览 基于<springboot - 映射 /error 到自定义且实现了ErrorController的Controller>改造,仅将MyCustomErrorController ...

  10. ESP8266 SDK开发: 外设篇-串口

    串口分布 串口切换说明 1.默认所有的数据都使用串口0输出 官方提供了函数可以选择printf利用哪一个串口输出 配置printf使用串口1打印输出,波特率115200 (注:这样配置对于调试程序很有 ...