[SDOI2009]HH去散步 「矩阵乘法计数」

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

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

矩阵乘法计数

对于计数问题,若可以将 \(n\) 个点表示成 \(n \times 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
*/

转载于:https://www.cnblogs.com/Colythme/p/10305288.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值