牛客小白赛13,E,矩阵乘法的实际意义,矩阵快速幂

题目链接:E-小A的路径

自己写的时候想跑SPFA,然后把每个点的入度乘以出度再求和。后来发现不对,对于任意一个点来说,有可能在多个不同的天数进入,这样就不好确定它到底是在哪天入队的,算法会变得非常复杂。

看完题解才想起来离散数学里面讲的可达矩阵,当时还手算五阶可达阵的六次方(课上手算,简直算得想死......)

那么另一个问题来了:矩阵快速幂。

以前也没写过矩阵快速幂,借着机会学一下了。

typedef long long ll;

struct Matrix{
    ll a[N][N];
    Matrix() { memset(a,0,sizeof(a)); }
    Matrix operator* (const Matrix &rhs) const {
        Matrix res;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                for(int k=1;k<=n;k++)
                    res.a[i][j]=(res.a[i][j]+a[i][k]*rhs.a[k][j])%mod;
        return res;
    }
}G,res;
 

void fpow(int k) {
    for(int i=1;i<=n;i++) res.a[i][i]=1; //n是阶数,相当于普通快速幂的 ans=1;
    while(k) {
        if(k&1) res=res*G;
        G=G*G;
        k>>=1; 
    }
}

另外,板子记不住就得自己写矩阵乘法,下面是伪代码:

matrix_multipul(res,G){
//原矩阵	G[n][n];
//结果矩阵 	res[n][n];
	for(int i = 1 ; i <= n ; i ++){
		for(int j = 1 ; j <= n ; j ++){
			for(int k = 1 ; k <= n ; k ++){
				res[i][j]=(res[i][j]+G[i][k]+G[k][j]);
			}
		}
	} 
	return res;
}

矩阵左乘和右乘的结果是不一样的,但是res和G的都是由G自乘得来的,可以验证此处乘法作为矩阵快速幂的子函数用,乘法顺序不影响结果。但是如果在其他的题目里面就要注意左乘还是右乘。

牛客网标程:https://ac.nowcoder.com/acm/contest/view-submission?submissionId=40519540

//标程 
#pragma GCC optimize(3,"Ofast","inline")
#include
#define pb push_back
#define Rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
typedef long double ld;
const int inf=0x3f3f3f3f;
const ll INF=9e18;
const int N=1e2+50;
const ll mod=1e9+7;
int n,m,k,s;
struct Matrix{
    ll a[N][N];
    Matrix() { memset(a,0,sizeof(a)); }
    Matrix operator* (const Matrix &rhs) const {
        Matrix res;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                for(int k=1;k<=n;k++)
                    res.a[i][j]=(res.a[i][j]+a[i][k]*rhs.a[k][j])%mod;
        return res;
    }
}G,res;
void fpow(int k) {
    while(k) {
        if(k&1) res=res*G;
        G=G*G;
        k>>=1; 
    }
}
int main() {    
    scanf("%d%d%d%d",&n,&m,&k,&s);
    for(int i=1;i<=m;i++) {
        int u,v;
        scanf("%d%d",&u,&v);
        G.a[u][v]++;
    }
    for(int i=1;i<=n;i++) res.a[i][i]=1; 
    fpow(k);
    ll sum=0;
    for(int i=1;i<=n;i++)
        if(i!=s) sum+=res.a[s][i],sum%=mod;
    printf("%lld\n",sum);
    return 0;
}

 

你可能感兴趣的:(牛客小白赛13,E,矩阵乘法的实际意义,矩阵快速幂)