zoukankan      html  css  js  c++  java
  • [SDOI2009]HH去散步 「矩阵乘法计数」

    计数问题也许可以转化为矩阵乘法形式

    比如若该题没有不能在一条边上重复走的条件限制,那么直接将邻接矩阵转化为矩阵乘法即可

    矩阵乘法计数

    对于计数问题,若可以将 (n) 个点表示成 (n imes n) 的矩阵,并且可以保证中途转移对象不会变化,即可用矩阵乘法计数

    至于该题

    那么考虑该题,加入了不能重复在一条边上走的限制,那么最简单的思想就是拆点,并且让改点屏蔽掉当前方向,但是如果考虑边,一条无向边可以拆成两条有向边,那拆出来的就比点少很多了,故考虑点边转化

    那么只要在起始点加一条超级源边,同样矩阵乘法即可统计答案

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    
    #define MOD 45989
    
    using namespace std;
    
    typedef long long LL;
    
    const int MAXN = 50 + 10;
    const int MAXM = 120 + 10;
    
    struct LinkedForwardStar {
    	int to;
    
    	int next;
    } ;
    
    LinkedForwardStar Link[MAXM];
    int Head[MAXN]= {0};
    int size = 1;
    
    void Insert (int u, int v) {
    	Link[++ size].to = v;
    	Link[size].next = Head[u];
    
    	Head[u] = size;
    }
    
    int N, M, K;
    int st, ed;
    
    struct Matrix {
    	LL a[MAXM][MAXM];
    
    	void init () {
    		for (int i = 1; i <= size; i ++)
    			for (int j = 1; j <= size; j ++)
    				a[i][j] = 0;
    	}
    	Matrix operator * (const Matrix& p) const {
    		Matrix newmat;
    		newmat.init ();
    		for (int i = 1; i <= size; i ++)
    			for (int j = 1; j <= size; j ++)
    				for (int k = 1; k <= size; k ++)
    					newmat.a[i][j] = (newmat.a[i][j] + a[i][k] * p.a[k][j] % MOD) % MOD;
    		return newmat;
    	}
    } ;
    Matrix mats, bem;
    
    LL power (int p) {
    	while (p) {
    		if (p & 1)
    			mats = mats * bem;
    		bem = bem * bem;
    		p >>= 1;
    	}
    	LL ans = 0;
    	for (int i = Head[ed]; i; i = Link[i].next)
    		ans = (ans + mats.a[1][i ^ 1]) % MOD;
    	return ans;
    }
    
    int getnum () {
    	int num = 0;
    	char ch = getchar ();
    
    	while (! isdigit (ch))
    		ch = getchar ();
    	while (isdigit (ch))
    		num = (num << 3) + (num << 1) + ch - '0', ch = getchar ();
    
    	return num;
    }
    
    int main () {
    	N = getnum (), M = getnum (), K = getnum (), st = getnum () + 1, ed = getnum () + 1;
    	for (int i = 1; i <= M; i ++) {
    		int u = getnum () + 1, v = getnum () + 1;
    		Insert (u, v), Insert (v, u);
    	}
    	for (int i = Head[st]; i; i = Link[i].next)
    		bem.a[1][i] = 1;
    	for (int i = 2; i <= size; i ++) {
    		int v = Link[i].to;
    		for (int j = Head[v]; j; j = Link[j].next) {
    			if ((j ^ 1) == i)
    				continue;
    			bem.a[i][j] = 1;
    		}
    	}
    	for (int i = 1; i <= size; i ++)
    		mats.a[i][i] = 1;
    	LL ans = power (K);
    	cout << ans << endl;
    
    	return 0;
    }
    
    /*
    4 5 3 0 0
    0 1
    0 2
    0 3
    2 1
    3 2
    */
    
  • 相关阅读:
    微信朋友圈怎么发文字?如何只发文字和表情?
    微信将推指纹支付 "指付通"会与Touch ID整合吗
    微信公众平台上传图片很卡 微信整合京东的关系?
    微信公众平台可以修改名称吗?微信认证时可以改名!
    怎样制作漂亮的微信二维码?用在线二维码生成器!
    微信网页版APP
    织梦channelid是什么?dede channel typeid有什么区别
    微信消息如何添加文字链接?【微信公众平台技巧】
    为什么在有些文章末尾加一张收录截图?
    5步教你设置微信自定义菜单【微信公众平台技巧】
  • 原文地址:https://www.cnblogs.com/Colythme/p/10305288.html
Copyright © 2011-2022 走看看