一些特殊的矩阵快速幂 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}. 在构造求 ...
随机推荐
- 一个无法解析的外部命令and无法解析的外部符号
出现错误: 解决: 因为修改了函数定义的参数,但是没有修改函数声明的参数 把参数统一一下就行了
- [Vue]vue-router嵌套路由(子路由)
总共添加两个子路由,分别命名Collection.vue(我的收藏)和Trace.vue(我的足迹) 1.重构router/index.js的路由配置,需要使用children数组来定义子路由,具体如 ...
- [Vue]避免 v-if 和 v-for 用在同一个元素上
一般我们在两种常见的情况下会倾向于这样做: 情形1:为了过滤一个列表中的项目 (比如 v-for="user in users" v-if="user.isActive& ...
- R语言做逻辑回归
前面写过一个多分类的逻辑回归,现在要做一个简单的二分类,用glm函数 导入csv格式如下: mydata<-read.csv("D://li.csv",header=T) c ...
- java 框架-分布式文件管理系统1FastDFS
https://www.cnblogs.com/chiangchou/p/fastdfs.html
- C#使用Selenium网页自动化
工作中很多时候经常需要网抓数据或者把数据填写到网站上,使用Selenium将其自动化是一种不错的选择.Selenium其实是一个用于Web应用程序测试的工具,测试你的应用程序看是否能够很好地工作在不同 ...
- INTEL_BIOS 编译—for-ATOM_E3800
INTEL_BIOS 编译—for-ATOM_E3800 ======================================================================= ...
- 12.java中参数传递机制---形参和实参
1.形参:用来接收调用该方法时传递的参数.只有在被调用的时候才分配内存空间,一旦调用结束,就释放内存空间.因此仅仅在方法内有效. public void swap(int a, int b) { in ...
- [转载]JDK、SDK、J2EE、J2SE、J2ME的区别
[转载]JDK.SDK.J2EE.J2SE.J2ME的区别 来源: https://www.cnblogs.com/liangyihui/p/5905875.html Java的名词真的是多啊 JDK ...
- Visual Stdio C++ 编译常见问题
1. new 数组出现崩溃 new 数组时数组下标出现负值,但未做出错处理: new数组,数组字节数大于4MB的时候有可能出现crash! 解决办法: 加入 try catch 后,这样的错误几乎没 ...