矩阵快速幂在ACM中的应用

16计算机2黄睿博

首发于个人博客http://www.cnblogs.com/BobHuang/

作为一个acmer,矩阵在这个算法竞赛中还是蛮多的,一个优秀的算法可以影响到一个程序的运行速度的快慢,在算法竞赛中常常采用快速幂算法,因为有些递推式及有些问题都可以化为矩阵,所以矩阵快速幂也就有了意义。

首先引入快速幂:

我们要求a^b,那么其实b是可以拆成二进制的,该二进制数第i位的权为2^(i-1),

例如当b=11时  11的二进制是1011

11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1因此,我们将a¹¹转化为算 因为存在这一相等关系,所以将O(n)复杂度的算法降到了O(logn),代码如下

int poww(int x, int n)
{
int ans=;
while(n)
{
if(n&)ans=ans*x;
x=x*x;
n>>=;
}
return ans;
}

这里面用到了一些奇怪的运算,位运算,关于这个详见我的另一篇博客(>>相当于/2,&1相当于判断末位是否为1,比较接近计算机底层,取模还有除法运算常数比较大)

我的矩阵快速幂模板

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=;
int G;
struct MX
{
ll v[N][N];
void O()
{
memset(v,,sizeof v);
}
void E()
{
memset(v,,sizeof v);
for(int i=; i<G; i++)v[i][i]=;
}
void P()
{
for(int i=; i<G; i++)
for(int j=; j<G; j++)printf(j==G-?"%d\n":"%d ",v[i][j]);
}
MX operator+(const MX &b) const
{
MX c;
c.O();
for(int i=; i<G; i++)
for(int j=; j<G; j++)c.v[i][j]=v[i][j]+b.v[i][j];
return c;
}
MX operator*(const MX &b)const
{
MX c;
c.O();
for(int k=; k<G; k++)
for(int i=; i<G; i++)
if(v[i][k])for(int j=; j<G; j++)c.v[i][j]+=v[i][k]*b.v[k][j];
return c;
}
MX operator^(int p)const
{
MX y,x;
y.E(),memcpy(x.v,v,sizeof(v));
for(; p; x=x*x,p>>=)if(p&)y=y*x;
return y;
}
} a,ans;

目前c/c++最大支持__int128,也就是最大的有符号整数为2^127-1,数量级大概是1e38,不过常用的还是long long,是长整形,2^63-1。所以常用一个MOD质数的方法,这样得到的答案更加丰富。

引入完毕,接下来进入正题,无非是将以上的乘法转换为矩阵乘法。

我们从最简单的斐波那契数列入手,求菲波那切数列的第n项,n很大,所以MOD1e9+7

斐波的为前两项之和,即发f[0]=1,f[1]=1,f[i] = f[i-1]+f[i-2](i>1)

比较简单的可以直接得到递推式

,进一步递推

由于矩阵乘法满足结合律,所它也可以用快速幂算法求解。

代码如下

struct Matrix
{
long long a[][];
Matrix()
{
memset(a,,sizeof(a));
}
Matrix operator*(const Matrix y)
{
Matrix ans;
for(int i=; i<=; i++)
for(int j=; j<=; j++)
for(int k=; k<=; k++)
ans.a[i][j]+=a[i][k]*y.a[k][j];
for(int i=; i<=; i++)
for(int j=; j<=; j++)
ans.a[i][j]%=M;
return ans;
}
void operator=(const Matrix b)
{
for(int i=; i<=; i++)
for(int j=; j<=; j++)
a[i][j]=b.a[i][j];
}
};
long long solve(long long x)
{
Matrix ans,t;
ans.a[][]=ans.a[][]=;
t.a[][]=t.a[][]=t.a[][]=;
while(x)
{
if(x&)ans=ans*t;
t=t*t;
x>>=;
}
return ans.a[][];
}

强行递推式

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int mod = ;
unordered_map<ll,ll> M;
ll fic(ll x)
{
if(M.count(x))return M[x];
ll a=(x+)/,b=x/+;
return M[x]=((fic(a)*fic(b))%mod+(fic(a-)*fic(b-)))%mod;
}
int main()
{
ll n;
M[]=,M[]=M[]=;
cin>>n;
cout<<fic(n);
return ;
}

如果经过推理得到一个递推式呢

如果对矩阵乘法还是不太懂的话,可以先看下这个知乎回答

例子HDU2842

Dumbear likes to play the Chinese Rings (Baguenaudier). It’s a game played with nine rings on a bar. The rules of this game are very simple: At first, the nine rings are all on the bar.

The first ring can be taken off or taken on with one step.

If the first k rings are all off and the (k + 1)th ring is on, then the (k + 2)th ring can be taken off or taken on with one step. (0 ≤ k ≤ 7)

Now consider a game with N (N ≤ 1,000,000,000) rings on a bar, Dumbear wants to make all the rings off the bar with least steps. But Dumbear is very dumb, so he wants you to help him.

九连环:如果要拆第n个环,那么第n-1个环就必须在竿上,

前n-2个环都必须已经被拆下,题目是现在是一个n连环,求将n连环全部

拆掉需要的最少的步骤%200907.

如果前k个环被拆掉,第k+1个还被挂着,那么第k+2个就可以拿下或者装上

f[n] = 2 * f[n - 2] + f[n - 1] + 1

就是f(n)=f[n-1]+2*f[n-2]+1,f[n-1]=1*f[n-1],1=1;

就是可以从前两个状态推到当前状态,这个关系矩阵的系数还是比较好找的

下一个例子

n个六边形排成一行,相邻两个六边形共用一条边,如下图所示:

记这个图形的生成树个数为t(n)(由于每条边都是不同的,不存在同构的问题)。那么t(1)=6,t(2)=35……

给出n,求 mod 1000000007

第i个矩形右边那条边会不会去掉的方案数

dp[i][1]=dp[i-1][0]+dp[i-1][1],

dp[i][0]=4*dp[i-1][1]+5*dp[i-1][0]

i个六边形总个数就是dp[i][0] + dp[i][1];

矩阵就是

分析下dp[i+1][2],这一项已经做了前缀和,所以和之前的总数是不一样的

dp[i+1][2]=dp[i+1][1]+dp[i+1][0]+dp[i][2]=dp[i][0]+dp[i][1]+4dp[i][0]+5dp[i-1][1]+dp[i][2]

=5dp[i][0]+6dp[i][1]+dp[i][2]

所以这个就很好解决了

假设a[i]为当前项的前缀和,很容易发现

a[i] =6*a[i-1] - a[i-2] +5

这个用矩阵怎么填呢

可以这样填,还有看到他们最后把a[0][0]-1的,但是相信懂了矩阵乘法的你懂这戏额都是在干嘛

(因为初值的设置不同)

 最后一个例子

一个n位数,它的每位都是奇数,且数字1和3出现偶数次,这样的n位数有多少个。比如说n=1,只有3个,它们分别是5,7和9。让你求下满足这些条件的数的个数MOD9973,对于给定的n都会包含有四种状态,1和3的个数都是奇数;1是奇数,3是偶数;1是偶数,3是奇数;1是偶数,3是偶数。

1是偶数,3是偶数是我想要的状态

在相互转换中其实是可以直接写出系数的

a[0][3]是我们要的状态即为所求

代码如下

#include <stdio.h>
#include <string.h>
const int MD=;
struct matrix
{
int mat[][];
};
matrix matmul(matrix a,matrix b,int n)
{
int i,j,k;
matrix c;
memset(c.mat,,sizeof(c.mat));
for(i=; i<n; i++)
{
for(j=; j<n; j++)
{
for(k=; k<n; k++)
{
c.mat[i][j]=(c.mat[i][j]+a.mat[i][k]*b.mat[k][j])%MD;
} }
}
return c;
}
matrix matpow(matrix a,int k,int n)
{
matrix b;
int i;
memset(b.mat,,sizeof(b.mat));
for(i=; i<n; i++) b.mat[i][i]=;
while(k)
{
if(k&) b=matmul(a,b,n);
a=matmul(a,a,n);
k>>=;
}
return b;
}
int main()
{
int k;
while(~scanf("%d",&k))
{
matrix a,b,ans;
memset(a.mat,,sizeof(a.mat));
memset(b.mat,,sizeof(b.mat));
a.mat[][]=;
for(int i=; i<; i++)
{
for(int j=; j<; j++)
{
if(i==j) b.mat[i][j]=;
else if(i+j==) b.mat[i][j]=;
else b.mat[i][j]=;
}
}
ans=matmul(a,matpow(b,k,),);
printf("%d\n",ans.mat[][]);
}
return ;
}

矩阵快速幂在ACM中的应用的更多相关文章

  1. 2020牛客寒假算法基础集训营1 J. 缪斯的影响力 (矩阵快速幂/费马小定理降幂)

    https://ac.nowcoder.com/acm/problem/200658 f(n) = f(n-1) * f(n-2) * ab ,f的第一项是x,第二项是y. 试着推出第三项是x·y·a ...

  2. HDU 3802 矩阵快速幂 化简递推式子 加一点点二次剩余知识

    求$G(a,b,n,p) = (a^{\frac {p-1}{2}}+1)(b^{\frac{p-1}{2}}+1)[(\sqrt{a} + \sqrt{b})^{2F_n} + (\sqrt{a} ...

  3. UOJ424 Count 生成函数、多项式求逆、矩阵快速幂

    传送门 两个序列相同当且仅当它们的笛卡尔树相同,于是变成笛卡尔树计数. 然后注意到每一个点的权值一定会比其左儿子的权值大,所以笛卡尔树上还不能够存在一条从根到某个节点的路径满足向左走的次数\(> ...

  4. POJ 2778 DNA Sequence ( AC自动机、Trie图、矩阵快速幂、DP )

    题意 : 给出一些病毒串,问你由ATGC构成的长度为 n 且不包含这些病毒串的个数有多少个 分析 : 这题搞了我真特么久啊,首先你需要知道的前置技能包括 AC自动机.构建Trie图.矩阵快速幂,其中矩 ...

  5. 计蒜客 ACM训练联盟周赛 第一场 Alice和Bob的Nim游戏 矩阵快速幂

    题目描述 众所周知,Alice和Bob非常喜欢博弈,而且Alice永远是先手,Bob永远是后手. Alice和Bob面前有3堆石子,Alice和Bob每次轮流拿某堆石子中的若干个石子(不可以是0个), ...

  6. 华东交通大学2018年ACM“双基”程序设计竞赛 C. 公式题 (2) (矩阵快速幂)

    题目链接:公式题 (2) 比赛链接:华东交通大学2018年ACM"双基"程序设计竞赛 题目描述 令f(n)=2f(n-1)+3f(n-2)+n,f(1)=1,f(2)=2 令g(n ...

  7. [技术]浅谈OI中矩阵快速幂的用法

    前言 矩阵是高等代数学中的常见工具,也常见于统计分析等应用数学学科中,矩阵的运算是数值分析领域的重要问题. 基本介绍 (该部分为入门向,非入门选手可以跳过) 由 m行n列元素排列成的矩形阵列.矩阵里的 ...

  8. 2017 ECJTU ACM程序设计竞赛 矩阵快速幂+二分

    矩阵 Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other) Total Submission ...

  9. 2017 ACM/ICPC Asia Regional Shenyang Online:number number number hdu 6198【矩阵快速幂】

    Problem Description We define a sequence F: ⋅ F0=0,F1=1;⋅ Fn=Fn−1+Fn−2 (n≥2). Give you an integer k, ...

随机推荐

  1. ArcGIS Server 10.1发布GP服务

    ArcGIS Server 10.1发布GP服务 ArcGIS Server 10.1发布GP服务确实更简单了,只是刚使用不怎么习惯.ArcGIS Server 10.1发布GP服务需要先在ArcCa ...

  2. Windows使用MySQL数据库管理系统中文乱码问题

    声明:本文关于MySQL中文乱码问题的解决方案均基于Windows 10操作系统,如果是Linux系统会有较多不适用之处,请谨慎参考. 一.MySQL中文乱码情况 1. sqlDevelper远程登陆 ...

  3. VMware与Hyper-V不兼容

    一.问题描述 VMware Workstation与Hyper-V不兼容. 二.解决方案 取消Hyper-V功能,即将Hyper-V框中钩去掉. 三.总结思考 开始不清楚怎么解决这个问题,主要原因在于 ...

  4. 机器学习经典算法之SVM

    SVM 的英文叫 Support Vector Machine,中文名为支持向量机.它是常见的一种分类方法,在机器学习中,SVM 是有监督的学习模型. 什么是有监督的学习模型呢?它指的是我们需要事先对 ...

  5. UVA 1152 4 Values Whose Sum is Zero 和为0的4个值 (中途相遇)

    摘要:中途相遇.对比map,快排+二分查找,Hash效率. n是4000的级别,直接O(n^4)肯定超,所以中途相遇法,O(n^2)的时间枚举其中两个的和,O(n^2)的时间枚举其他两个的和的相反数, ...

  6. noip模拟赛#45

    T1:n<=1e6,求最小的区间包含(1,m)的所有数. =>双指针扫一遍即可 #include<cstdio> #include<cstring> #includ ...

  7. python解析xml实例

    如下,一个银行卡打标签后导出的数据 <?xml version="1.0" encoding="ISO-8859-1"?> <annotati ...

  8. Memcache使用基础

    Memcached的特点:     协议简单     基于libevent的事件处理     内置内存存储方式     memcached不互相通信的分布式   1.协议简单:     使用简单的基于 ...

  9. Vue处理ajax请求

    Ajax请求 1>解决跨域问题 1.1前端解决.只需要在vue.config.js中增加devServer节点增加代理: const path = require("path" ...

  10. ssh整合思想 Spring与Hibernate的整合ssh整合相关JAR包下载 .MySQLDialect方言解决无法服务器启动自动update创建表问题

    除之前的Spring相关包,还有structs2包外,还需要Hibernate的相关包 首先,Spring整合其他持久化层框架的JAR包 spring-orm-4.2.4.RELEASE.jar  ( ...