一些特殊的矩阵快速幂 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}. 在构造求 ...
随机推荐
- Comet OJ Contest #3
A:签到. #include<bits/stdc++.h> using namespace std; #define ll long long #define inf 1000000010 ...
- 0160 十分钟看懂时序数据库(I)-存储
摘要:2017年时序数据库忽然火了起来.开年2月Facebook开源了beringei时序数据库:到了4月基于PostgreSQL打造的时序数据库TimeScaleDB也开源了,而早在2016年7月, ...
- (十五)Activitivi5之多用户任务分配
一.概念 我们在开发的时候,有一种情况是这样的, 我们有一个任务,可以让多个用户中的任何一个人办理即可,比如某个审批任务, 张三,李四,王五他们中的任何一人办理下都行,这时候,我们用到多用户任务分配. ...
- (二)shiro之jsp标签
一.介绍 <%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %> Guest ...
- 利用jwt生成token,用于http请求身份验证
前段时间在做移动端接口过程中,考虑到安全性,所有移动端发送请求(除了登录请求)过程中进行token有效验证. 1.利用jwt生成token a.导入jwt相关包 <!-- jwt --> ...
- http协议与soap协议之间的区别
http是标准超文本传输协议.使用对参数进行编码并将参数作为键值对传递,还使用关联的请求语义.每个协议都包含一系列HTTP请求标头及其他一些信息,定义客户端向服务器请求哪些内容,服务器用一系列HTTP ...
- 基于【 MySql 】一 || 主从复制
一.centos7安装mysql 1. 先检查系统是否装有mysql rpm -qa | grep mysql 2. 下载mysql的repo源 wget http://repo.mysql.com/ ...
- swoole| swoole 协程初体验 转
swoole| swoole 协程初体验 date: 2018-5-30 14:31:38title: swoole| swoole 协程初体验description: 通过协程的执行初窥 swo ...
- centos7安装harbor
harbor是什么? docker容器是集装箱,harbor就是放集装箱的港湾. 一.下载软件: github上选择对应版本下载 https://github.com/goharbor/harbor/ ...
- No valid host was found. There are not enough hosts available-----openstack建虚拟机直接报错
目录 No valid host was found. There are not enough hosts available-----openstack建虚拟机直接报错 一.问题现象: 二.解决思 ...