思想启发来自,

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

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

一开始,最一般的矩阵快速幂,要斐波那契数列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. springboot项目在IDEA根据不同的开发人员读取不同的配置文件

    IDEA启动项目打开项目的配置文件,修改Program argument为--spring.profiles.active=developerName启动项目,即可 命令行方式启动项目 java -j ...

  2. hdu 1698 线段数的区间更新 以及延迟更新

    先说说区间更新和单点更新的区别 主要的区别是搜索的过程 前者需要确定一个区间 后者就是一个点就好了 贴上两者代码 void updata(int i)//单点更新 { int l=stu[i].l; ...

  3. 使用隔离级别read committed隐式解决并发冲突

    1.使用rc的弊端:出现不可重复读 Oracle不可重复读 Oracle丢失修改 Oracle幻读 任何数据库的update  insert  delete都加排它锁 sql server的selec ...

  4. AngularJS视图 ng-view

    AngularJS支持通过在单个页面上的多个视图的单页应用.要做到这一点AngularJS提供ng-view 和 ng-template指令,以及 $routeProvider 服务. ng-view ...

  5. Abp 添加权限项<一>

    1.下载代码,数据库迁移,npm install 2.添加权限项: public static class PermissionNames { public const string Pages_Te ...

  6. WeChat App Word

    chats:聊天:n werun:微信运动 contacts:联系人:n official accounts:官方账号(公众号) discover:发现:vi moments:片刻(朋友圈动态):n ...

  7. 史上最简单Git入门教程

    一:Git是什么? Git是目前世界上最先进的分布式版本控制系统. 工作原理 / 流程: Workspace:工作区Index / Stage:暂存区Repository:仓库区(或本地仓库)Remo ...

  8. Docker启动Elasticsearch报错java.nio.file.AccessDeniedException

    报错信息 Caused by: java.nio.file.AccessDeniedException: /usr/share/elasticsearch/data/nodes 问题分析 表面上是说容 ...

  9. C++ STL 之 函数对象适配器

    谓词是指普通函数或重载的 operator()返回值是 bool 类型的函数对象(仿函数).如果operator 接受一个参数,那么叫做一元谓词,如果接受两个参数,那么叫做二元谓词,谓词可作为一个判断 ...

  10. js获取URL请求参数与改变src

    js实现: <script> function GetQueryString(name) { var reg = new RegExp("(^|&)" + na ...