矩阵模板hdu5015,UVA 10655,UVA 11149

Posted by Cww97 on 2016-08-13

版权声明:本文为博主原创文章,未经博主允许不得转载。原文所在http://blog.csdn.net/cww97 https://blog.csdn.net/cww97/article/details/52196784
hdu5015

n是<=10的,可以想到点什么,,
构造矩阵mat[n+2][n+2]
这里写图片描述
发现mat*a是答案矩阵第1列
mat的m次方再乘a就是答案矩阵的第m列,取最下面的就行了

这板不错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
typedef long long ll;
const int P = 10000007;
const int N=13;
ll n,m;

struct matrix{
ll a[N][N];
int row,col;
matrix():row(N),col(N){
memset(a,0,sizeof(a));
}
matrix(int x,int y):row(x),col(y){
memset(a,0,sizeof(a));
}
ll* operator [] (int x){
return a[x];
}
matrix operator * (matrix x){
matrix tmp ;
for (int i=0;i<=n+1;i++)
for (int j=0;j<=n+1;j++){
tmp[i][j]=0;
for (int k=0;k<=n+1;k++)
tmp[i][j]=(tmp[i][j]+a[i][k]*x[k][j])%P;
}
return tmp;
}
void operator *= (matrix x){
*this = *this * x;
}
matrix operator ^ (ll x){
matrix ret;
for (int i=0;i<=n+1;i++)ret[i][i]=1;
matrix tmp = *this;
for (;x;x>>=1,tmp*=tmp){if(x&1)ret *=tmp;}
return ret;
}
void print(){
for (int i=0;i<=n+1;i++){
for (int j=0;j<=n+1;j++)
printf("%d ",a[i][j]);
puts("");
}
}
};

matrix getMatrix(){
matrix mat;
mat[0][0]=10;
mat[0][n+1]=1;
for (int i=1;i<=n;i++)
for (int j=0;j<=i;j++)mat[i][j]=1;
for (int i=0;i<=n;i++)mat[n+1][i]=0;
mat[n+1][n+1]=1;
return mat;
}

int main(){
//freopen("fuck.in","r",stdin);
while (~scanf("%I64d%I64d",&n,&m)){
matrix a;
for (int i=1;i<=n;i++)scanf("%I64d",&a[i][0]);
a[0][0] = 233,a[n+1][0] = 3;
matrix mat = getMatrix();
mat = (mat ^ m) * a;
printf("%I64d\n",mat[n][0]%P);
}
return 0;
}

UVA 10655
题解
题目大意:给出a+b的值和ab的值,求an+bn的值。

题目分析:有种错误的方法是这样的:利用已知的两个方程联立,求解出a和b,进而求出答案。这种方法之所以错,是因为这种方法有局限性。联立之后会得到一个二元一次方程,只有当该方程有实数解确切的说是当某个数据满足该方程有实数解时,这种方法得到的结果才有可能正确。显然,题中数据不可能这么片面。正确的方法是这样的:

令a+b=A,ab=B,S(n)=an+bn。
则S(n)=an+bn=(a+b)(an-1+bn-1)-abn-1-an-1b
=(a+b)(an-1+bn-1)-ab(an-2+bn-2)=AS(n-1)-BS(n-2) (n≥2)。

由此构造2x2的矩阵:
matrix[1][1]=A,matrix[1][2]=-B;
matrix[2][1]=1,matrix[2][2]=0;

n=1或n=0时,答案显然。

要注意:数据中可能会出现A=B=0的情况,此时a=b=0,所以不能简单的判定当A=B=0时就结束输入数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
typedef long long ll;
const int N=4;

struct matrix{
ll a[N][N];
int row,col;
matrix():row(N),col(N){
memset(a,0,sizeof(a));
}
matrix(int x,int y):row(x),col(y){
memset(a,0,sizeof(a));
}
ll* operator [] (int x){
return a[x];
}
matrix operator * (matrix x){
matrix tmp ;
for (int i=1;i<=2;i++)
for (int j=1;j<=2;j++){
tmp[i][j]=0;
for (int k=1;k<=2;k++)
tmp[i][j]=(tmp[i][j]+a[i][k]*x[k][j]);
}
return tmp;
}
void operator *= (matrix x){
*this = *this * x;
}
matrix operator ^ (ll x){
matrix ret;
for (int i=1;i<=2;i++)ret[i][i]=1;
matrix tmp = *this;
for (;x;x>>=1,tmp*=tmp){if(x&1)ret *=tmp;}
return ret;
}
void operator ^=(ll x){
*this = *this ^ x;
}
void print(){
for (int i=1;i<=2;i++){
for (int j=1;j<=2;j++)
printf("%d ",a[i][j]);
puts("");
}
}
};

ll solve(ll a ,ll b ,ll n){
if (n==0) return 2;
if (n==1) return a;
if (a==0&&b==0)return 0;
matrix tra,ans;
tra[1][1]=a;tra[1][2]=-b;
tra[2][1]=1;tra[2][2]=0;
ans[1][1]=a;
ans[2][1]=2;
ans = (tra^n)*ans;
return ans[2][1];
}

int main(){
//freopen("fuck.in","r",stdin);
ll p,q,n;
while (scanf("%lld%lld%lld",&p,&q,&n)==3){
printf("%lld\n",solve(p,q,n));
}
return 0;
}

UVA 11149
题解
题目大意:给一个n阶方阵,求A1+A2+A3+……Ak。

题目分析:令F(k)=A1+A2+A3+……Ak。当k为偶数时,F(k)=F(k/2)_(E+Ak/2),k为奇数时,F(k)=F(k/2)_(E+Ak/2)+Ak。证明这两条公式也很简单,把这两条公式展开就行了。根据公式,递归即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/*
* UVA 11149 Power of Matrix
* by cww97
*/
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
typedef long long ll;
const int N=43;
int n;

struct matrix{
ll a[N][N];
int row,col;
matrix():row(N),col(N){
memset(a,0,sizeof(a));
}
matrix(int x,int y):row(x),col(y){
memset(a,0,sizeof(a));
}
ll* operator [] (int x){
return a[x];
}
matrix operator + (matrix x){
matrix tmp ;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++){
tmp[i][j]=(a[i][j]+x[i][j])%10;
}
return tmp;
}
void operator += (matrix x){
*this = *this + x;
}
matrix operator * (matrix x){
matrix tmp ;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++){
tmp[i][j]=0;
for (int k=1;k<=n;k++)
tmp[i][j]=(tmp[i][j]+a[i][k]*x[k][j])%10;
}
return tmp;
}
void operator *= (matrix x){
*this = *this * x;
}
matrix operator ^ (ll x){
matrix ret;
for (int i=1;i<=n;i++)ret[i][i]=1;
matrix tmp = *this;
for (;x;x>>=1,tmp*=tmp){if(x&1)ret *=tmp;}
return ret;
}
void operator ^=(ll x){
*this = *this ^ x;
}
void print(){
for (int i=1;i<=n;i++){
for (int j=1;j<n;j++)
printf("%d ",a[i][j]%10);
printf("%d\n",a[i][n]%10);
}
puts("");
}
}E,A;

matrix f(int k){
if (k==1)return A;
matrix tmp = f(k>>1)*((A^(k>>1)) +E);
if (k&1)tmp +=(A^k);
return tmp;
}

int main(){
//freopen("fuck.in","r",stdin);
int k,x;
while (scanf("%d%d",&n,&k)==2&&n){
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++){
scanf("%d",&x);
A[i][j]=x%10;
}
}
for (int i=1;i<=n;i++)E[i][i]=1;
A = f(k);
A.print();
}
return 0;
}