矩阵的乘法运算
typedef vector<int> vi
typedef vector<vi> mat
mat mul(mat A,mat B){
mat C(sz(A),vi(sz(B[0]));
for(int i=0;i<sz(A);i++)
for(int k=0;k<sz(B);k++)
for(int j=0;j<sz(B[0];j++)
C[i][j]+=A[i][k]*B[k][j];
return C;
}
基本性质
乘法结合律: (AB)C=A(BC)
乘法左分配律:(A+B)C=AC+BC
乘法右分配律:C(A+B)=CA+CB
对数乘的结合性k(AB)=(kA)B=A(kB)
矩阵乘法一般不满足交换律
应用
<1>例如我们要求斐波那契数列的第x项;
我们可以这样构造
![]()
有由于乘法结合律所以
typedef vector<int> vi
typedef vector<vi> mat
mat mul(mat A,mat B){
mat C(sz(A),vi(sz(B[0]));
for(int i=0;i<sz(A);i++)
for(int k=0;k<sz(B);k++)
for(int j=0;j<sz(B[0];j++)
C[i][j]=1ll*C[i][j]+A[i][k]*B[k][j]%P;
return C;
}
mat pow(mat A,int n){
mat C(sz(A),vi(sz(A[0])));
for(int i=0;i<sz(A);i++)C[i][i]=1;//相当于{1}
while(n){
if(n&1)C=mul(A,C);
A=mul(A,A);
n>>=1;
}return C;
}
int solve(){
mat(2,vi(2));
A[0][0]=1;A[0][1]=1;
A[1][0]=1;A[1][1]=0;
A=pow(A,n-1);
return A[0][0];
}
<2>题意:在一条满是地雷的路上,起点在1处。在N个点处布有地雷, 1<=N<=10 。地雷点的坐标范围每次前进p的概率前进一步,1-p的概率前进2步。问顺利通过这条路的概率。 n <
18
我们可以把路分成n段即
1~ pos[1] ;
pos[1] +1~ pos[2] ;
pos[2] +1~ pos[3] ;
…
对于每一段我们一步一步的DP
用 dp[i] 表示走到第i处的可能性
于是可以成功通过这一段的可能性为 1−dp[pos[i]]
#include<stdio.h>
#include<algorithm>
#include<iostream>
using namespace std;
struct mat{
double Mat[2][2];
mat(){Mat[0][1]=Mat[0][0]=Mat[1][0]=Mat[1][1]=0;}
mat operator *(const mat&A)const{
mat B;
for(int i=0;i<2;i++)
for(int k=0;k<2;k++)
for(int j=0;j<2;j++)
B.Mat[i][j]+=A.Mat[i][k]*Mat[k][j];
return B;
}
};
mat pow(mat a,int n){
mat ret;
for(int i=0;i<2;i++)ret.Mat[i][i]=1;
while(n){
if(n&1)ret=ret*a;
a=a*a;
n>>=1;
}return ret;
}
int x[30],n;
int main(){
double p;
while(~scanf("%d",&n)){
cin>>p;
for(int i=1;i<=n;i++)scanf("%d",x+i);
sort(1+x,1+x+n);
double ans=1;
mat tt,nw,tmp;
tt.Mat[0][0]=p;
tt.Mat[0][1]=1-p;
tt.Mat[1][0]=1;
nw.Mat[0][0]=1;
for(int i=1;i<=n;i++){
if(x[i]==x[i-1])continue;
tmp=pow(tt,x[i]-x[i-1]-1);
tmp=nw*tmp;
ans*=(1-tmp.Mat[0][0]);
}
printf("%.7f\n",ans);
}
return 0;
}