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;
    }
    
  • 相关阅读:
    服务器状态码
    QuerySet中添加Extra进行SQL查询
    django配置一个网站建设
    MySQL数据库查询中的特殊命令
    125. Valid Palindrome
    121. Best Time to Buy and Sell Stock
    117. Populating Next Right Pointers in Each Node II
    98. Validate Binary Search Tree
    91. Decode Ways
    90. Subsets II
  • 原文地址:https://www.cnblogs.com/Hs-black/p/11756425.html
Copyright © 2011-2022 走看看