1 条题解

  • 0
    @ 2025-8-24 21:39:17

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar hs_black
    Go for broke

    搬运于2025-08-24 21:39:17,当前版本为作者最后更新于2019-10-28 23:53:14,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


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

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

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

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

    下面考虑G2G^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;
    	}
    

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

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

    以此类推

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

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

    回到本题

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

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

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

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

    答案为 a[0]k/12a[1]a[2]s[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;
    }
    
    • 1

    信息

    ID
    1617
    时间
    1000ms
    内存
    125MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者