一些特殊的矩阵快速幂 hdu5950 hdu3369 hdu 3483
思想启发来自,
对于矩阵乘法和矩阵快速幂就不多重复了,网上很多博客都有讲解。主要来学习一下系数矩阵的构造
一开始,最一般的矩阵快速幂,要斐波那契数列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的更多相关文章
- 矩阵快速幂AC代码HDU 2035
#include <iostream> using namespace std;const int MOD = 1000;//像这样的一个常量就应该专门定义一下 int PowMod(in ...
- HDU5950 Recursive sequence —— 矩阵快速幂
题目链接:https://vjudge.net/problem/HDU-5950 Recursive sequence Time Limit: 2000/1000 MS (Java/Others) ...
- 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 ...
- 【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 < ...
- HDU5950 Recursive sequence (矩阵快速幂加速递推) (2016ACM/ICPC亚洲赛区沈阳站 Problem C)
题目链接:传送门 题目: Recursive sequence Time Limit: / MS (Java/Others) Memory Limit: / K (Java/Others) Total ...
- HDU5950 Recursive sequence 非线性递推式 矩阵快速幂
题目传送门 题目描述:给出一个数列的第一项和第二项,计算第n项. 递推式是 f(n)=f(n-1)+2*f(n-2)+n^4. 由于n很大,所以肯定是矩阵快速幂的题目,但是矩阵快速幂只能解决线性的问题 ...
- HDU5950【矩阵快速幂】
主要还是i^4化成一个(i+1)^4没遇到过,还是很基础的一题矩阵快速幂: #include <bits/stdc++.h> using namespace std; typedef lo ...
- HDU5950 矩阵快速幂(巧妙的递推)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5950 题意:f[n] = 2*f[n-2] + f[n-1] + n^4 思路:对于递推题而言,如果递 ...
- RecursiveSequence(HDU-5950)【矩阵快速幂】
题目链接: 题意:Si=S(i-1)+2*S(i-2)+i^4,求Sn. 思路:想到了矩阵快速幂,实在没想出来怎么构造矩阵.... 首先构造一个向量vec={a,b,16,8,4,2,1}. 在构造求 ...
随机推荐
- java中的自动装箱和拆箱
一.什么是自动装箱和拆箱: 我们知道java为8种基本类型分别提供了对应的包装类型,在Java SE5之前,如果要生成一个数值为10的Integer对象,必须这样进行: Integer i=new I ...
- SpringBoot 第一篇:HelloWorld 跑起来
背景 金融行业从业快十年,作为银行系开发人员来说开源框架了解不多非常正常,因为银行系的运行平台,基本上不会采购小厂商集合开源框架自建的产品,竞标的产品没有几十个成功案例,你也进不了这个门槛(有关系的除 ...
- js中new到底做了什么?
1.创建一个新的obj; 2.让obj_proto_=Func.prototype; 3.Func.call(obj);
- Seaborn(一)之风格管理
Seaborn简介 seaborn同matplotlib一样,也是Python进行数据可视化分析的重要第三方包.但seaborn是在 matplotlib的基础上进行了更高级的API封装,使得作图更加 ...
- Rsync同步过程中遇到的常见问题
一.Rsync服务介绍 Rsync属于一款实现全量及增量同步数据的软件工具,适用于unix/linux/windows等多种操作系统平台. Rsync软件能实现本地复制,远程复制,或者远程守护进程方式 ...
- mysql 创建用户,授权,查询用户等
MySQL创建用户与授权 一. 创建用户 命令: CREATE USER 'username'@'host' IDENTIFIED BY 'password'; 说明: username:你将创建的用 ...
- 1.NIO概述
/*Java NIO 简介*/ java NIO (New IO)是从 java1.4版本开始引入的一个新的IO API,可以替代标准的 java IO API (jdk1.7又对其进行了改进, 称为 ...
- Oracle 找到引起账户锁定的IP
在ORACLE数据库中,如果没有修改过FAILED_LOGIN_ATTEMPTS的话,默认10次尝试失败后就会锁住用户.此时再登录数据库,就会遇到ORA-28000: the account is l ...
- Computer Vision_33_SIFT:Evaluation of Interest Point Detectors——2000
此部分是计算机视觉部分,主要侧重在底层特征提取,视频分析,跟踪,目标检测和识别方面等方面.对于自己不太熟悉的领域比如摄像机标定和立体视觉,仅仅列出上google上引用次数比较多的文献.有一些刚刚出版的 ...
- 基于OPENldap搭建postfix 虚拟用户
本文首发: https://www.somata.work/2019/DependOPENldapBuildPostfixVirtualMailUser.html postfix + dovecot ...