zoukankan      html  css  js  c++  java
  • BZOJ1898. [Zjoi2005]Swamp 沼泽鳄鱼

    机房大佬讲解后, 写一写题解

    这是很经典的邻接矩阵乘法了

    对于邻接矩阵G[i][j] 表示i到j有没有边

    如果是(G^1) , 发现就是原矩阵, G[i][j]可以理解为从i走一步到j的方案数

    下面考虑(G^2)

    矩阵乘法代码:

    Matrix operator * (const Martix &p) const{
    		Martix tmp;
    		for (rint i = 0;i < n; i++) 
    			for (rint j = 0;j < n; j++) 
    				for (rint k = 0;k < n; k++) 
    					tmp.Mar[i][j] = (tmp.Mar[i][j] + Mar[i][k] * p.Mar[k][j]) % P;
    		return tmp;
    	}
    

    发现(G^2[i][j] = sum_{k=0}^{n-1} G[i][k] * G[k][j]) 像不像Floyd

    即枚举一个中间点k, 从i到j走两步的的方案数等于从i到走一步k的方案数, 再乘上从k走一步到j的方案数之和

    以此类推

    (G^t[i][j])为再G这个邻接矩阵上从i走t步到j的方案数

    原矩阵(G^0)为单位矩阵, 每乘一个新的邻接矩阵相当于又在新的邻接矩阵上走一步

    回到本题

    2, 3, 4的最小公倍数为12

    所以开十二个邻接矩阵即可, 每个矩阵表示当前走一步的合法情况

    a[0]表示走12步的矩阵, 即12个邻接矩阵之积

    k/12个a[0]相乘使用快速幂, 在按顺序从a[1]乘到a[k%12]

    答案为 (a[0]^{k/12} * a[1] * a[2] * cdots s[k\%12])

    细节见代码及注释:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    using namespace std;
    template <typename T> 
    void read(T &x) {
    	x = 0; int f = 1;
    	char c = getchar();
    	for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
    	for (;isdigit(c);c=getchar()) x = (x << 3) + (x << 1) + c - '0';
    	x *= f;
    }//快读
    const int N = 52;
    int n, m;
    ll t, k;
    const int P = 10000;
    #define rint register int
    struct matrix{
    	int Mar[N][N];
    	matrix () {
    		memset(Mar, 0, sizeof(Mar));
    	}
    	matrix operator * (const matrix &p) const{
    		matrix tmp;
    		for (rint i = 0;i < n; i++) 
    			for (rint j = 0;j < n; j++) 
    				for (rint k = 0;k < n; k++) 
    					tmp.Mar[i][j] = (tmp.Mar[i][j] + Mar[i][k] * p.Mar[k][j]) % P;
    		return tmp;
    	}//矩阵乘法
    	void print(void) {
    		for (int i = 0;i < n; i++) {
    			for (int j = 0;j < n; j++) 
    				printf ("%d ", Mar[i][j]);
    			cout << endl;
    		}
    		cout << endl;
    	}//调试输出
    }a[15], b, c;
    
    matrix pow() {
    	matrix ans = b, tmp = a[0];
    	int tttmp = k / 12;
    	while (tttmp) {
    		if (tttmp & 1) ans = ans * tmp;
    		tmp = tmp * tmp;
    		tttmp >>= 1;
    	}
    	return ans;
    }//矩阵快速幂
    int nfish, ttmp[50], st, ed;			
    int main() {
    //	freopen("hs.out","w",stdout);
    	read(n), read(m), read(st), read(ed), read(k);
    	while (m--) {
    		int x, y;
    		read(x), read(y);
    		c.Mar[x][y] = c.Mar[y][x] = 1; //原矩阵
    	}
    //	c.print();
    	for (rint i = 1;i <= 12; i++) a[i] = c; //初始化
    	for (rint i = 0;i < n; i++) b.Mar[i][i] = 1; //单位矩阵
    	read(nfish);
    	while (nfish--) {
    		read(t);
    		for (int i = 0;i < t; i++) read(ttmp[i]); ttmp[t] = ttmp[0]; 
            	//由于开始时时间为0, 所以读入要从零开始
    		for (int i = 1;i <= 12; i++) 
    			for (int j = 0;j < n; j++) 
    				a[i].Mar[j][ttmp[(i-1)%t+1]] = 0; 
            		//注意只清空从其他地方到鳄鱼新来的地点的边
    	}
    //	for (int i = 1;i <= 12; i++) a[i].print();
    	a[0] = b;
    	for (int i = 1;i <= 12; i++) a[0] = a[0] * a[i];	
    //	a[0].print();
    	matrix ans = pow();
    	for (int i = 1;i <= k % 12; i++) ans = ans * a[i];
    	cout << ans.Mar[st][ed] << endl;
    	return 0;
    }
    
  • 相关阅读:
    分布式事务
    K8s应用案例介绍——阿里云
    数据库索引的底层原理——b树
    Understanding the GitHub flow
    Code Review
    详解微服务架构
    yarn之package.json
    yarn.lock文件
    Git Api——git开发
    Unit Test —— xUnit.net
  • 原文地址:https://www.cnblogs.com/Hs-black/p/11756425.html
Copyright © 2011-2022 走看看