Luogu 4159 [SCOI2009]迷路

BZOJ 1297

应当是简单题。

发现边权的数量很小,所以我们暴力把一个点拆成$9$个点,然后把$(x, i)$到$(x, i + 1)$连边,代表转移一次之后可以走回来;对于每一条存在的边$(i, j, k)$,把$(i, k)$向$(j, 1)$连边,代表走一条路。然后用这个矩阵乘$T$次即可,这样子最后的答案$ans = [(1, 1)][(n, 1)]$格子的值。

记$m = 9 * n$,时间复杂度为$O(m^3logT)$。

Code:

#include <cstdio>
#include <cstring>
using namespace std;

const int N = 15;
const int M = 105;
const int P = 2009;

int n, tim;

inline void inc(int &x, int y) {
    x += y;
    if(x >= P) x -= P;
}

inline int id(int x, int k) {
    return (x - 1) * 9 + k;
}

struct Matrix {
    int len, wid, s[M][M];

    inline void init(int r, int c) {
        len = r, wid = c;
        memset(s, 0, sizeof(s));
    } 

    friend Matrix operator * (const Matrix &x, const Matrix &y) {
        Matrix res; res.init(x.len, y.wid);
        for(int k = 1; k <= x.wid; k++)
            for(int i = 1; i <= x.len; i++)
                for(int j = 1; j <= y.wid; j++)
                    inc(res.s[i][j], x.s[i][k] * y.s[k][j] % P);
        return res;
    }

    inline void print() {
        for(int i = 1; i <= len; i++, printf("\n"))
            for(int j = 1; j <= wid; j++)
                printf("%d ", s[i][j]);
    }

} f;

inline Matrix fpow(Matrix x, int y) {
    Matrix res; res.init(x.len, x.wid);
    for(int i = 1; i <= x.len; i++) res.s[i][i] = 1;
    for(; y > 0; y >>= 1) {
        if(y & 1) res = res * x;
        x = x * x;
    }
    return res;
}

int main() {
    scanf("%d%d", &n, &tim);
    f.init(9 * n, 9 * n);
    for(int i = 1; i <= n; i++) {
        char str[N];
        scanf("%s", str + 1);
        for(int j = 1; j <= n; j++) {
            int k = str[j] - '0';
            if(!k) continue;
            f.s[id(i, k)][id(j, 1)] = 1;
        }

        for(int j = 2; j <= 9; j++)
            f.s[id(i, j - 1)][id(i, j)] = 1;
    }

//    f.print();

    f = fpow(f, tim);
 //   f.print();

    printf("%d\n", f.s[id(1, 1)][id(n, 1)]);
    return 0;
}
View Code

 

posted @ 2018-10-21 08:25  CzxingcHen  阅读(105)  评论(0编辑  收藏  举报