zoukankan      html  css  js  c++  java
  • Luogu 2151 [SDOI2009]HH去散步

    BZOJ 1875

    矩阵乘法加速递推。

    如果不要求不能走同一条边,那么直接构造出矩阵快速幂即可,但是不走相同的道路,怎么办?

    发现边数$m$也很小,我们直接把$2 * m$开成一个矩阵,相当于记录上一条边走过了编号为$j$的边的方案总数,这样子我们在构造转移矩阵的时候就可以不用计算往回走带来的贡献了。

    时间复杂度$O(m^3log(MaxInt))$。

    Code:

    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    
    const int N = 55;
    const int M = 125;
    const int P = 45989;
    
    int n, m, tot = 0, from[M], to[M];
    
    template <typename T>
    inline void read(T &X) {
        X = 0; char ch = 0; T op = 1;
        for(; ch > '9' || ch < '0'; ch = getchar())
            if(ch == '-') op = -1;
        for(; ch >= '0' && ch <= '9'; ch = getchar())
            X = (X << 3) + (X << 1) + ch - 48;
        X *= op;
    }
    
    template <typename T>
    inline void inc(T &x, T y) {
        x += y;
        if(x >= P) x -= P;
    }
    
    struct Matrix {
        int len, wid, s[M][M];
    
        inline void init() {
            len = wid = 0;
            memset(s, 0LL, sizeof(s));
        } 
    
        friend Matrix operator * (const Matrix &x, const Matrix &y) {
            Matrix res; res.init();
            res.len = x.len, res.wid = y.wid;
            for(int k = 0; k < x.wid; k++)
                for(int i = 0; i < x.len; i++)
                    for(int j = 0; j < y.wid; j++)
                        inc(res.s[i][j], (int) (1LL * x.s[i][k] * y.s[k][j] % P));
            return res;
        }
    
    } f, tra;
    
    inline Matrix fpow(Matrix x, int y) {
        Matrix res; res.init();
        res.len = x.len, res.wid = x.wid;
        for(int i = 0; i < res.len; i++) res.s[i][i] = 1;
    
        for(; y > 0; y >>= 1) {
            if(y & 1) res = res * x;
            x = x * x;
        }
    
        return res;
    }
    
    inline int opp(int now) {
        return (now & 1) ? now + 1 : now - 1;
    }
    
    int main() {
        int tim, st, ed;
        read(n), read(m), read(tim), read(st), read(ed);
        for(int x, y, i = 1; i <= m; i++) {
            read(x), read(y);
            ++tot, from[tot] = x, to[tot] = y;
            ++tot, from[tot] = y, to[tot] = x;
        }
    
        f.init();f.len = 1, f.wid = 2 * m;
        for(int i = 1; i <= tot; i++)
            if(from[i] == st) ++f.s[0][i - 1];
        tra.init(); tra.len = tra.wid = 2 * m;
        for(int i = 1; i <= tot; i++)
            for(int j = 1; j <= tot; j++) {
                if(j == i || j == opp(i)) continue;
                if(to[i] == from[j]) 
                    ++tra.s[i - 1][j - 1];
            }
        
        tra = fpow(tra, tim - 1);
        f = f * tra;
    
        int ans = 0;
        for(int i = 1; i <= tot; i++)
            if(to[i] == ed) inc(ans, f.s[0][i - 1]);
        
        printf("%d
    ", ans);
        return 0;
    }
    View Code
  • 相关阅读:
    3 Steps to Perform SSH Login Without Password Using sshkeygen & sshcopyid
    排序算法java版,速度排行:冒泡排序、简单选择排序、直接插入排序、折半插入排序、希尔排序、堆排序、归并排序、快速排序
    Ubuntu 取消 Apache及MySQL等自启动
    linux screen 命令详解
    Ubuntu把家目录文件夹名称改为英文
    Ubuntu12.10 下 PPA安装搜狗输入法 for Linux
    VirtualBox虚拟机后台运行
    Ubuntu下安装jdk
    [整理篇]linux加入windows域之完美方案
    pxe 远程安装linux系统
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9815894.html
Copyright © 2011-2022 走看看