矩阵专题训练1
来源:互联网 发布:快手表白神器软件 编辑:程序博客网 时间:2024/05/29 08:37
HDU 1757
http://acm.hdu.edu.cn/showproblem.php?pid=1757
题意很清楚不同的X对应不同的FX,而且当X>=10时,有一个递推公式,因为N比较大,所以简单的暴力去写肯定不可能,所以要构造矩阵用快速幂解决。。。
思路:前10个FX简单保存下值,然后当X>=10时构造10*10的进行快速幂的矩阵 和10*1的初始矩阵。
大致可以写成/*****************************************
|0 1 0 0 0 0 0 0 0 0 | |f(x-10)| |f(x-9)|
|0 0 1 0 0 0 0 0 0 0 | |f(x-9) | |f(x-8)|
|0 0 0 1 0 0 0 0 0 0 | |f(x-8) | |f(x-7)|
|0 0 0 0 1 0 0 0 0 0 | |f(x-7) | |f(x-6)|
|0 0 0 0 0 1 0 0 0 0 |* |f(x-6) |= |f(x-5)|
|0 0 0 0 0 0 1 0 0 0 | |f(x-5) | |f(x-4)|
|0 0 0 0 0 0 0 1 0 0 | |f(x-4) | |f(x-3)|
|0 0 0 0 0 0 0 0 1 0 | |f(x-3) | |f(x-2)|
|0 0 0 0 0 0 0 0 0 1 | |f(x-2) | |f(x-1)|
|a9 a8 a7 a6 a5... a1| |f(x-1) | |f(x) |
******************************************/然后就O了,当时代码写的较矬 我自己都看不懂了。。。
#include<cstdio>#include<cstring>#include<cmath>#include<iostream>#include<algorithm>using namespace std;int a[10][10];int ans[10];int k,m;int f[20];int b[10];void fun(){ memset(f,0,sizeof(f)); for(int i=0;i<=9;i++) { f[i]=i; f[i]%=m; } for(int i=10;i<20;i++) { for(int j=0;j<=9;j++) { f[i]+=(b[j]*f[i-j-1])%m; f[i]%=m; } }}void cheng1(){ int temp[10]; memset(temp,0,sizeof(temp)); for(int i=0;i<10;i++) { for(int j=0;j<10;j++) { temp[i]+=(ans[j]*a[j][i])%m; temp[i]%=m; } } for(int i=0;i<10;i++) { ans[i]=temp[i]; }}void cheng2(){ int temp1[10][10]; memset(temp1,0,sizeof(temp1)); for(int i=0;i<10;i++) { for(int j=0;j<10;j++) { for(int k=0;k<10;k++) { temp1[i][j]+=(a[i][k]*a[k][j])%m; temp1[i][j]%=m; } } } for(int i=0;i<10;i++) { for(int j=0;j<10;j++) { a[i][j]=temp1[i][j]; } }}int main(){ while(cin>>k>>m) { memset(a,0,sizeof(a)); for(int i=0;i<10;i++) { cin>>b[i]; a[i][0]=b[i]; } for(int i=1;i<10;i++) { a[i-1][i]=1; } fun(); if(k<=19) { cout<<f[k]<<endl; } else { k=k-19; for(int i=0;i<10;i++) { ans[i]=f[19-i]; } while(k) { if(k%2==0) { cheng2(); k/=2; } else { cheng1(); k--; } } cout<<ans[0]<<endl; } } return 0;}POJ 3233
求 S = A + A2 + A3 + … +Ak.
思路:对矩阵进行二分求和,若K为奇数,多出来的那个数直接快速幂,剩余的进行二分求和,然后二分进行递归按照是奇数单独拿一个去快速幂的思路可以敲出。
http://poj.org/problem?id=3233
#include<cstdio>#include<cstring>#include<cmath>#include<iostream>#include<algorithm>using namespace std;struct juzhen{int m[30][30];};int n,k,mod;juzhen mut(juzhen a,juzhen b){ juzhen c; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { c.m[i][j]=0; for(int k=0;k<n;k++) { c.m[i][j]+=(a.m[i][k]*b.m[k][j])%mod; c.m[i][j]%=mod; } } } return c;}juzhen add(juzhen a,juzhen b){ juzhen c; memset(c.m,0,sizeof(c.m)); for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { c.m[i][j]+=(a.m[i][j]+b.m[i][j])%mod; c.m[i][j]%=mod; } } return c;}juzhen pow(juzhen a,int p){ juzhen c; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { if(i==j) { c.m[i][j]=1; } else { c.m[i][j]=0; } } } while(p) { if(p%2==0) { a=mut(a,a); p/=2; } else { c=mut(c,a); p--; } } return c;}juzhen erfen(juzhen a,int p){ if(p==1) return a; if(p==2) return add(a,mut(a,a)); if(p%2==1) { return add(erfen(a,p-1),pow(a,p)); } if(p%2==0) { juzhen c; c=erfen(a,p/2);//这里先进行二分省的进入递归时每次再进行这步操作可以提高效率。。一开始没优化狂T。 return add(c,mut(pow(a,p/2),c)); }}int main(){ scanf("%d%d%d",&n,&k,&mod); juzhen a; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { scanf("%d",&a.m[i][j]); } } a=erfen(a,k); for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { printf("%d ",a.m[i][j]); } printf("\n"); } return 0;}
HDU 1588
http://acm.hdu.edu.cn/showproblem.php?pid=1588
也是矩阵二分求和,而且F是斐波那契矩阵只不过注意F(G(n))=F(K*n+b)=a^b(a^0+a^k+a^2k+a^3k+...a^(n-1)*k)
#include<cstdio>#include<cstring>#include<cmath>#include<iostream>#include<algorithm>using namespace std;struct juzhen{long long m[2][2];};long long k,b,n,M;juzhen mut(juzhen a,juzhen b){ juzhen c; for(long long i=0;i<2;i++) { for(long long j=0;j<2;j++) { c.m[i][j]=0; for(long long k=0;k<2;k++) { c.m[i][j]+=(a.m[i][k]*b.m[k][j])%M; c.m[i][j]%=M; } } } return c;}juzhen add(juzhen a,juzhen b){ juzhen c; memset(c.m,0,sizeof(c.m)); for(long long i=0;i<2;i++) { for(long long j=0;j<2;j++) { c.m[i][j]+=(a.m[i][j]+b.m[i][j])%M; c.m[i][j]%=M; } } return c;}juzhen pow(juzhen a,long long p){ juzhen b; b.m[0][0]=b.m[1][1]=1; b.m[0][1]=b.m[1][0]=0; while(p) { if(p%2==0) { a=mut(a,a); p/=2; } else { b=mut(b,a); p--; } } return b;}juzhen erfen(juzhen a,long long p){ if(p==1) return a; if(p==2) return add(a,mut(a,a)); if(p%2==1) { return add(erfen(a,p-1),pow(a,p)); } if(p%2==0) { juzhen c; c=erfen(a,p/2); return add(c,mut(pow(a,p/2),c)); }}int main(){ while(cin>>k>>b>>n>>M) { juzhen a; a.m[0][0]=a.m[0][1]=a.m[1][0]=1; a.m[1][1]=0; juzhen aa; aa=pow(a,b); juzhen bb; bb=pow(a,k); juzhen cc; cc=erfen(bb,n-1); juzhen dd; dd=mut(aa,cc); juzhen ans; ans=add(aa,dd); cout<<ans.m[0][1]<<endl; } return 0;}
HDU 3306
http://acm.hdu.edu.cn/showproblem.php?pid=3306
Now we define another kind of Fibonacci : A(0) = 1 , A(1) = 1 , A(N) = X * A(N - 1) + Y * A(N - 2) (N >= 2).And we want to Calculate S(N) , S(N) = A(0)2 +A(1)2+……+A(n)2.
首先把AN平方有A(N)^2=X^2*A(N-1)^2+Y^2*A(N-2)^2+2*X*Y*A(N-1)*A(N-2) ,根据这个式子可以构造:
|1 x*x y*y 2*x*y| | SUMN | | SUMN+1 |
|0 x*x y*y 2*x*y| | A(N-1)^2 | | A(N)^2 |
|0 1 0 0 |* | A(N-2)^2 |=| A(N-1)^2 |
|0 x 0 y | |A(N-1)*A(N-2)| | A(N)*A(N-1) |
特别注意A(N)*A(N-1)=(X*A(N-1)+Y*A(N-2))*A(N-1)=X*A(N-1)^2+Y*A(N-1)*(N-2)故最后一阶构造成0 X 0 Y的形式
剩下的。。就是注意取余的问题了。。
当然如果下次要求SUM类的矩阵记得在原定义的矩阵上多加一阶用来存放SUM的值然后就O了。
#include<cstdio>#include<cstring>#include<cmath>#include<iostream>#include<algorithm>using namespace std;int n,x,y;const int mod=10007;struct juzhen {int m[4][4];};juzhen mut(juzhen a,juzhen b){ juzhen c; for(int i=0;i<4;i++) { for(int j=0;j<4;j++) { c.m[i][j]=0; for(int k=0;k<4;k++) { c.m[i][j]+=(a.m[i][k]*b.m[k][j])%mod; c.m[i][j]%=mod; } } } return c;}juzhen pow(juzhen a,int p){ juzhen b; memset(b.m,0,sizeof(b.m)); for(int i=0;i<4;i++) { b.m[i][i]=1; } while(p) { if(p%2==0) { a=mut(a,a); p/=2; } else { b=mut(b,a); p--; } } return b;}int main(){ while(cin>>n>>x>>y) { juzhen a; x%=mod; y%=mod; a.m[0][0]=a.m[2][1]=1; a.m[1][0]=a.m[2][0]=a.m[3][0]=a.m[2][2]=a.m[2][3]=a.m[3][2]=0; a.m[0][1]=a.m[1][1]=(x*x)%mod; a.m[0][2]=a.m[1][2]=(y*y)%mod; a.m[0][3]=a.m[1][3]=(2*x*y)%mod; a.m[3][1]=x%mod; a.m[3][3]=y%mod; juzhen ans; ans=pow(a,n-1); int sum; sum=(2*ans.m[0][0]+ans.m[0][1]+ans.m[0][2]+ans.m[0][3])%mod; cout<<sum<<endl; }return 0;}
今天先写简单写下四题。。大概刷了12题,然后明天有时间更新2和3,智商比较低代码比较挫还望勿见怪,实力有限。。还得继续努力。。。
.
- 矩阵专题训练1
- [专题训练]数论专题1
- 暑假训练1-搜索专题
- scau_专题1训练总结
- 矩阵专题
- 矩阵专题
- 【矩阵专题】
- 矩阵专题
- 蒟蒻DP专题训练1--HDU2955
- ACM专题训练
- HDU 专题训练
- 数论专题训练D
- 数论专题训练K
- 搜索专题训练(2)
- 数学专题训练2
- 数学专题训练3
- 数学专题训练4
- 线段树专题训练
- DataFu在Apache进入孵化状态
- 1075. PAT Judge
- HDU 2016 数据的交换输出
- java 人员信息查看程序
- LumiSoft收取邮件(含邮件附件)
- 矩阵专题训练1
- css hack搜集整理
- linux 以其他用户执行脚本
- 利用GetPrivateProfileString读取配置文件(.ini)
- log4j详解与实战
- [java] eclipse 插件开发
- 全概率公式:敏感问题的调查
- HDU 2017 字符串统计
- 站点页面身份验证问题