思想启发来自,

罗博士根据递推公式构造系数矩阵用于快速幂

对于矩阵乘法和矩阵快速幂就不多重复了,网上很多博客都有讲解。主要来学习一下系数矩阵的构造

一开始,最一般的矩阵快速幂,要斐波那契数列Fn=Fn-1+Fn-2的第n项,想必都知道可以构造矩阵来转移

其中,前面那个矩阵就叫做系数矩阵(我比较喜欢叫转移矩阵)

POJ3070 Fibonacci 可以试一试

 #include<cstdio>
typedef long long ll;
const ll md=;
struct Mar{
int r,c;
ll a[][];
Mar(){}
Mar(int r,int c):r(r),c(c){
for(int i=;i<r;i++)
for(int j=;j<c;j++) a[i][j]=;
}
}A,T;
Mar mul(Mar A,Mar B){
Mar ans(A.r,B.c);
for(int i=;i<A.r;i++)
for(int j=;j<B.c;j++)
for(int k=;k<A.c;k++){
ans.a[i][j]+=A.a[i][k]*B.a[k][j]%md;
if(ans.a[i][j]>=md) ans.a[i][j]-=md;
}
return ans;
}
Mar poww(Mar A,int b){
Mar ans(A.r,A.c);
for(int i=;i<A.r;i++) ans.a[i][i]=;
while(b){
if(b&) ans=mul(ans,A);
A=mul(A,A);
b>>=;
}
return ans;
}
void init(ll a,ll b){
A=Mar(,);
T=Mar(,);
A.a[][]=b;A.a[][]=a;
T.a[][]=T.a[][]=T.a[][]=;
}
int main(){
int t,n;
ll a,b;
while(~scanf("%d",&n)&&n!=-){
if(n==) printf("0\n");
else{
init(,);
T=poww(T,n);
A=mul(T,A);
printf("%lld\n",A.a[][]);
}
}
return ;
}

昭哥说都是水题

然后像类斐波那契数列Fn=a*Fn-1+b*Fn-2 ,也就变一下系数矩阵

而如果是要求斐波那契的前n项和,除去我们知道的第n+2项-1,那对于类斐波那契的前n项和,我们可以设Sn=Sn-1+Fn,然后构造系数矩阵

然后对于一些递推公式,转换一下前后几项的关系,也可以构造相应的系数矩阵来矩阵快速幂求解,比如求Σix的前n项和的话,设Fn=nx,Sn=Sn-1+Fn

那么nx可以写成(n-1+1)x的形式,把n-1设为a,1设为b,然后就是二项式定理展开了,(二项式展开看右边→_→)

我们就可以得到一个n-1向n转移的递推过程,nx=Cxx(n-1)x+Cxx(n-1)x-1+...+C0x (n-1)0就可以构造系数矩阵

Recursive sequence HDU - 5950

题意:F1=a,F2=b,Fn=Fn-1+2*Fn-2+n4,给出n求Fn

 #include<cstdio>
typedef long long ll;
const ll md=;
struct Mar{
int r,c;
ll a[][];
Mar(){}
Mar(int r,int c):r(r),c(c){
for(int i=;i<r;i++)
for(int j=;j<c;j++) a[i][j]=;
}
}A,T;
Mar mul(Mar A,Mar B){
Mar ans(A.r,B.c);
for(int i=;i<A.r;i++)
for(int j=;j<B.c;j++)
for(int k=;k<A.c;k++){
ans.a[i][j]+=A.a[i][k]*B.a[k][j]%md;
if(ans.a[i][j]>=md) ans.a[i][j]-=md;
}
return ans;
}
Mar poww(Mar A,int b){
Mar ans(A.r,A.c);
for(int i=;i<A.r;i++) ans.a[i][i]=;
while(b){
if(b&) ans=mul(ans,A);
A=mul(A,A);
b>>=;
}
return ans;
}
void init(ll a,ll b){
A=Mar(,);
T=Mar(,);
A.a[][]=b;A.a[][]=a;
for(int i=,j=;i>=;i--,j<<=) A.a[i][]=j;
T.a[][]=;T.a[][]=;T.a[][]=;
for(int i=;i>=;i--){
T.a[i][]=;
for(int j=;j>=i;j--)
T.a[i][j]=T.a[i+][j]+T.a[i+][j+];
}
for(int i=;i<;i++) T.a[][i]=T.a[][i];
}
int main(){
int t,n;
ll a,b;
scanf("%d",&t);
while(t--){
scanf("%d%lld%lld",&n,&a,&b);
if(n==) printf("%lld\n",a%md);
else if(n==) printf("%lld\n",b%md);
else{
init(a,b);
T=poww(T,n-);
A=mul(T,A);
printf("%lld\n",A.a[][]);
}
}
return ;
}

+1说这是她去年就懂做的题

那么(an+b)x的前n项和呢,还是把n写成n-1+1的形式,然后(a(n-1)+1+b)x二项式分解

(an+b)x=Cxx(n-1)x*ax*(a+b)0+Cxx(n-1)x-1*ax-1*(a+b)1+...+C0x (n-1)0*a0*(a+b)x,然后构造系数矩阵

RobotHDU - 3369

题意:有个机器人第n天学nk个单词,但星期六和星期天休息,不学单词,给出n,k,问机器一共学了多少个单词。

我们已经可以求nk的前n项和了,那么接下来只需要求出星期六和星期天的再减去,即可。

那么,我们根据开始的星期几到下一个星期六距离的天数x,和下一个星期天距离的天数x+1,

那么要减去的部分就是,(7m1+x)k 和(7m2+x+1)k的前m项和m1=(n-x)/7,m2=(n-x-1)/7,且第一项分别是xk和(x+1)k

(转移矩阵懒得画了)

 #include<cstdio>
typedef long long ll;
const ll md=1e9+;
struct Mar{
int r,c;
ll a[][];
Mar(){}
Mar(int r,int c):r(r),c(c){
for(int i=;i<r;i++)
for(int j=;j<c;j++) a[i][j]=;
}
}A,T;
char s[];
ll cf[][];
Mar mul(Mar A,Mar B){
Mar ans(A.r,B.c);
for(int i=;i<A.r;i++)
for(int j=;j<B.c;j++)
for(int k=;k<A.c;k++){
ans.a[i][j]+=A.a[i][k]*B.a[k][j]%md;
if(ans.a[i][j]>=md) ans.a[i][j]-=md;
}
return ans;
}
Mar poww(Mar A,int b){
Mar ans(A.r,A.c);
for(int i=;i<A.r;i++) ans.a[i][i]=;
while(b){
if(b&) ans=mul(ans,A);
A=mul(A,A);
b>>=;
}
return ans;
}
void init(int n,ll f0,ll a,ll b){
A=Mar(n,);
T=Mar(n,n);
A.a[][]=f0,A.a[n-][]=;
for(int i=n-;i>=;i--){
T.a[i][n-]=;
for(int j=n-;j>=i;j--){
T.a[i][j]=T.a[i+][j]+T.a[i+][j+];
if(T.a[i][j]>=md) T.a[i][j]-=md;
}
}
T.a[][]=;
for(int i=;i<n;i++){
T.a[][i]=T.a[][i];
T.a[][i]*=cf[a][n--i];
if(T.a[][i]>=md) T.a[][i]%=md;
T.a[][i]*=cf[a+b][i-];
if(T.a[][i]>=md) T.a[][i]%=md;
}
}
ll solve(int n,int m,int x){
ll ans1,ans2,ans3;
init(m+,,,);T=poww(T,n);
A=mul(T,A);ans1=A.a[][];
init(m+,cf[x][m],,x);T=poww(T,(n-x)/);
A=mul(T,A);ans2=A.a[][];
init(m+,cf[x+][m],,x+);T=poww(T,(n-x-)/);
A=mul(T,A);ans3=A.a[][];
return ((((ans1-ans2)%md+md)%md-ans3)%md+md)%md;
}
int main(){
for(int i=;i<=;i++){
cf[i][]=;
for(int j=;j<=;j++){
cf[i][j]=cf[i][j-]*i;
if(cf[i][j]>=md) cf[i][j]%=md;
}
}
int t=,T,n,m,x;
scanf("%d",&T);
while(t<=T){
scanf("%s",s);
scanf("%d%d",&n,&m);
if(s[]=='M') x=;
else if(s[]=='T'&&s[]=='u') x=;
else if(s[]=='W') x=;
else if(s[]=='T') x=;
else if(s[]=='F') x=;
else if(s[]=='S'&&s[]=='a') x=;
else x=;
ll ans=solve(n,m,x);
printf("Case %d: %lld\n",t++,ans);
}
return ;
}

我也想学那么多单词

最后,如果是要求nxxn的前n项和呢,一样把n写成n-1+1,然后(n-1+1)xxn二项式分解

nxxn=Cxx(n-1)x*xn-1+1+Cxx(n-1)x-1*xn-1+1+...+C0x (n-1)0*xn-1+1,转移矩阵就有了

A Very Simple ProblemHDU - 3483

求nxxn的前n项和的模板题

 #include<cstdio>
typedef long long ll;
const int N=;
struct Mar{
int r,c;
ll a[N][N];
Mar(){}
Mar(int r,int c):r(r),c(c){
for(int i=;i<r;i++)
for(int j=;j<c;j++) a[i][j]=;
}
}A,T;
ll md ;
Mar mul(Mar A,Mar B){
Mar ans(A.r,B.c);
for(int i=;i<A.r;i++)
for(int j=;j<B.c;j++)
for(int k=;k<A.c;k++){
ans.a[i][j]+=A.a[i][k]*B.a[k][j]%md;
if(ans.a[i][j]>=md) ans.a[i][j]-=md;
}
return ans;
}
Mar poww(Mar A,int b){
Mar ans(A.r,A.c);
for(int i=;i<A.r;i++) ans.a[i][i]=;
while(b){
if(b&) ans=mul(ans,A);
A=mul(A,A);
b>>=;
}
return ans;
}
void init(int n,int x){
A=Mar(n,);
T=Mar(n,n);
A.a[n-][]=;
T.a[][]=;
for(int i=n-;i>=;i--){
T.a[i][n-]=;
for(int j=n-;j>=i;j--){
T.a[i][j]=T.a[i+][j]+T.a[i+][j+];
if(T.a[i][j]>=md) T.a[i][j]-=md;
}
}
for(int i=n-;i>=;i--)
for(int j=n-;j>=i;j--){
T.a[i][j]*=x;
if(T.a[i][j]>=md) T.a[i][j]%=md;
}
for(int i=;i<n;i++) T.a[][i]=T.a[][i];
}
int main(){
int n,x;
while(~scanf("%d%d%lld",&n,&x,&md)){
if(n<&&x<&&md<) break;
init(x+,x);
T=poww(T,n);
A=mul(T,A);
printf("%lld\n",A.a[][]);
}
return ;
}

啊,学到了

一些特殊的矩阵快速幂 hdu5950 hdu3369 hdu 3483的更多相关文章

  1. 矩阵快速幂AC代码HDU 2035

    #include <iostream> using namespace std;const int MOD = 1000;//像这样的一个常量就应该专门定义一下 int PowMod(in ...

  2. HDU5950 Recursive sequence —— 矩阵快速幂

    题目链接:https://vjudge.net/problem/HDU-5950 Recursive sequence Time Limit: 2000/1000 MS (Java/Others)   ...

  3. HDU5950(矩阵快速幂)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5950 题意:f(n) = f(n-1) + 2*f(n-2) + n^4,f(1) = a , f(2 ...

  4. 【HDU5950】Recursive sequence(矩阵快速幂)

    BUPT2017 wintertraining(15) #6F 题意 \(f(1)=a,f(2)=b,f(i)=2*(f(i-2)+f(i-1)+i^4)\) 给定n,a,b ,\(N,a,b < ...

  5. HDU5950 Recursive sequence (矩阵快速幂加速递推) (2016ACM/ICPC亚洲赛区沈阳站 Problem C)

    题目链接:传送门 题目: Recursive sequence Time Limit: / MS (Java/Others) Memory Limit: / K (Java/Others) Total ...

  6. HDU5950 Recursive sequence 非线性递推式 矩阵快速幂

    题目传送门 题目描述:给出一个数列的第一项和第二项,计算第n项. 递推式是 f(n)=f(n-1)+2*f(n-2)+n^4. 由于n很大,所以肯定是矩阵快速幂的题目,但是矩阵快速幂只能解决线性的问题 ...

  7. HDU5950【矩阵快速幂】

    主要还是i^4化成一个(i+1)^4没遇到过,还是很基础的一题矩阵快速幂: #include <bits/stdc++.h> using namespace std; typedef lo ...

  8. HDU5950 矩阵快速幂(巧妙的递推)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5950 题意:f[n] = 2*f[n-2] + f[n-1] + n^4 思路:对于递推题而言,如果递 ...

  9. RecursiveSequence(HDU-5950)【矩阵快速幂】

    题目链接: 题意:Si=S(i-1)+2*S(i-2)+i^4,求Sn. 思路:想到了矩阵快速幂,实在没想出来怎么构造矩阵.... 首先构造一个向量vec={a,b,16,8,4,2,1}. 在构造求 ...

随机推荐

  1. (八)装配Bean(2)

    二.在Java类中进行显式的装配 显式配置有两种: 1. 一种是在java(本文讲解)   2. 另一种是xml配置文件(第一章有讲) 案例一: 使用java显式装配+@autowired自动装配的方 ...

  2. docker 学习1 WSL docker ,Windows docker

    获取Linux内核版本 //使用 lsb_release -a 可见我电脑上的 WSL Linux 版本是 Ubuntu的. 安装docker for ubuntu (遇到问题) 转[http://b ...

  3. ElasticSearch创建动态索引

    ElasticSearch创建动态索引 需求:某实例需要按照月份来维护,所以之前的“写死”索引的方式当然不行了.通过百度和看SpringDataElasticSearch官方文档,最后解决了这个问题. ...

  4. $.ajax()属性详解

    $.ajax()方法详解 jquery中的ajax方法参数总是记不住,这里记录一下. 1.url: 要求为String类型的参数,(默认为当前页地址)发送请求的地址. 2.type: 要求为Strin ...

  5. js入门之函数

    一. 函数 函数可以封装一段特定功能的代码,然后通过函数名可以重复调用 1 .函数的定义 funcation 函数名 (){ 函数体 } 函数名() 调用函数 2. 函数的参数 funcation f ...

  6. buffers和cached

    buffers和cached是为了提高数据访问性能,减少对磁盘的I/O操作 buffers 用来给块设备做的缓冲大小 例如,目录内容,权限 cached 用来给文件做缓冲 例如,打开的文件 测试 先后 ...

  7. 8.读写锁ReadWriteLock

    /*ReadWriteLock 读写锁*/ private ReadWriteLock lock = new ReentrantReadWriteLock(); lock.readLock().loc ...

  8. zabbix-通过自动注册自动添加主机

    自动注册和自动发现可以实现一样的效果,就是自动添加符合条件的主机到监控,那跟自动发现有什么区别? 其实自动发现是由弊端的,上文也说到了,zabbix server是主动去扫描网段,寻找agent的,试 ...

  9. python 链接impala执行SQL

    项目中用python来链接impala数据库最常见,一个简单的链接,获取结果. #!/usr/bin/python # -*- coding:utf-8 -*- from impala.dbapi i ...

  10. Windows 下 mysql 安装

    mysql官网下载地址:https://downloads.mysql.com/archives/community/ 以5.7.20版本为例 首先安装包解压后,没有网上教程里面提到的data文件夹和 ...