参考 http://m.blog.csdn.net/article/details?id=52058209
应用篇
主要通过把数放到矩阵的不同位置,然后把普通递推式变成"矩阵的等比数列",最后快速幂求解递推式:
先通过入门的题目来讲应用矩阵快速幂的套路(会这题的也可以看一下套路):
例一: http://poj.org/problem?id=3070
题目:斐波那契数列f(n),给一个n,求f(n)%10000,n<=1e9;
(这题是可以用fibo的循环节去做的,不过这里不讲,反正是水题)
矩阵快速幂是用来求解递推式的,所以第一步先要列出递推式:
f(n)=f(n-1)+f(n-2)
第二步是建立矩阵递推式,找到转移矩阵:
,简写成T * A(n-1)=A(n),T矩阵就是那个2*2的常数矩阵,而
这里就是个矩阵乘法等式左边:1*f(n-1)+1*f(n-2)=f(n);1*f(n-1)+0*f(n-2)=f(n-1);
这里还是说一下构建矩阵递推的大致套路,一般An与A(n-1)都是按照原始递推式来构建的,当然可以先猜一个An,主要是利用矩阵乘法凑出矩阵T,第一行一般就是递推式,后面的行就是不需要的项就让与其的相乘系数为0。矩阵T就叫做转移矩阵(一定要是常数矩阵),它能把A(n-1)转移到A(n);然后这就是个等比数列,直接写出通项:此处A1叫初始矩阵。所以用一下矩阵快速幂然后乘上初始矩阵就能得到An,这里An就两个元素(两个位置),根据自己设置的A(n)对应位置就是对应的值,按照上面矩阵快速幂写法,res[1][1]=f(n)就是我们要求的。
给一些简单的递推式
1.f(n)=a*f(n-1)+b*f(n-2)+c;(a,b,c是常数)
2.f(n)=c^n-f(n-1) ;(c是常数)
http://poj.org/problem?id=3070
用结构体封装一下,代码会整洁一点。
const int N = 2;
const int mod = 10000;
struct matrix {
int m[N][N];
};
matrix multi(matrix a, matrix b)
{
matrix tmp;
memset(&tmp, 0, sizeof(tmp));
for (int i = 0; i < N; ++i)
for (int j = 0; j < N; ++j)
for (int k = 0; k < N; ++k)
{
tmp.m[i][j] += a.m[i][k] * b.m[k][j];
tmp.m[i][j] %= mod;
}
return tmp;
}
matrix Pow(matrix a, int n)
{
matrix res;
memset(&res, 0, sizeof(res));
for (int i = 0; i < N; ++i) res.m[i][i] = 1;
while (n)
{
if (n % 2 == 1)
res = multi(res, a);
a = multi(a, a);
n /= 2;
}
return res;
}
int main()
{
matrix a;
a.m[0][0] = 1;
a.m[0][1] = 1;
a.m[1][0] = 1;
a.m[1][1] = 0;
int n;
while (cin >> n && n!=-1)
{
matrix res = Pow(a, n);
cout << res.m[1][0] << endl;
}
system("pause");
}
http://poj.org/problem?id=3233
找到转移矩阵
要注意的是转移矩阵相乘的次数是k-1,因为一开始已经有一个S1了。
using namespace std;
const int N = 61;
int mod ;
struct matrix {
int m[N][N];
};
matrix multi(matrix a, matrix b,int n)
{
matrix tmp;
memset(&tmp, 0, sizeof(tmp));
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
for (int k = 0; k < n; ++k)
{
tmp.m[i][j] += a.m[i][k] * b.m[k][j];
tmp.m[i][j] %= mod;
}
return tmp;
}
matrix Pow(matrix a,long long k,int n)
{
matrix res;
memset(&res, 0, sizeof(res));
for (int i = 0; i < N; ++i) res.m[i][i] = 1;
while (k)
{
if (k % 2 == 1)
res = multi(res, a,n);
a = multi(a, a,n);
k /= 2;
}
return res;
}
void poj3323()
{
int n;
long long k;
matrix T,S;
cin >> n >> k >> mod;
memset(&T, 0, sizeof(T));
memset(&S, 0, sizeof(S));
for (int i = 0; i < n; ++i)
T.m[i][i] = 1;
for (int i = 0; i < n; ++i)
{
for (int j = n; j < 2*n; ++j)
{
cin >> T.m[i][j];
T.m[i + n][j] = T.m[i][j];
S.m[i][j - n] = T.m[i][j];
S.m[i + n][j - n] = T.m[i][j];
}
}
T = Pow(T, k-1, 2 * n); //注意传入参数是k-1
S = multi(T, S, 2 * n);
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
cout << S.m[i][j] << " ";
}
cout << endl;
}
}
int main()
{
poj3323();
}
http://acm.hdu.edu.cn/showproblem.php?pid=2276
这个跟网易面试题 魔力手环很像。
const int N = 101;
struct matrix {
int m[N][N];
};
matrix multi(matrix a, matrix b,int n)
{
matrix tmp;
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
{
tmp.m[i][j] = 0;
for (int k = 0; k < n; ++k)
{
tmp.m[i][j] ^= a.m[i][k] & b.m[k][j]; //这里从原来的模运算调优
}
}
return tmp;
}
matrix Pow(matrix a,long long k,int n)
{
matrix res;
memset(&res, 0, sizeof(res));
for (int i = 0; i < N; ++i) res.m[i][i] = 1;
while (k)
{
if (k&1)
res = multi(res, a,n);
a = multi(a, a,n);
k = k >>1;
}
return res;
}
void hdu2276()
{
int n,k;
char light[101];
matrix T,S;
while (scanf("%d",&k)!=EOF)
{
scanf("%s", light);
n = strlen(light);
memset(&T, 0, sizeof(T));
for (int i = 0; i < n; ++i)
{
T.m[i][i] = 1;
T.m[(i +n- 1) % n][i] = 1;
}
for(int i = 0; i0][i] = light[i]-'0';
}
T = Pow(T, k, n);
S = multi(S, T, n);
for (int i = 0; i < n; ++i)
{
printf("%d",S.m[0][i]);
}
printf("\n");
}
}
int main()
{
hdu2276();
}