【BZOJ 1297】[SCOI2009]迷路

【链接】 我是链接,点我呀:)
【题意】

在这里输入题意

【题解】

如果点与点之间的距离都是1的话。 那么T次方之后的矩阵上a[1][n]就是所求答案了。

但是这一题的边权可能会大于1
但最多为10

很容易想到拆点。

我们把每个点又重新分为9个点。
x1,x2,x3..x9
然后对于所有的i,从xi向x[i-1]连一条单向边。

然后如果x和y有一条长度为z的边
那么从x[1]向x[z-1]连一条边。
这样从x[1]走z条边才能到y[1]

然后在这个新的图所构成的矩阵上。

把它做一下矩阵乘法。
T次方
(这种方法,类似于强行把原图拆成边权都是1的图。用旧的方法,解决新的问题。
(很巧妙的转换

然后输出对应的位置就好。

【代码】

#include <bits/stdc++.h>
#define LL long long
#define rep1(i,a,b) for (int i = a;i <= b;i++)
#define rep2(i,a,b) for (int i = a;i >= b;i--)
#define all(x) x.begin(),x.end()
#define pb push_back
#define lson l,mid,rt<<1
#define ms(x,y) memset(x,y,sizeof x)
#define rson mid+1,r,rt<<1|1
using namespace std;

const double pi = acos(-1);
const int dx[4] = {0,0,1,-1};
const int dy[4] = {1,-1,0,0};
const int N = 100;

const int G = 100;       //矩阵大小
const LL MOD = 2009;    //模数
struct MX
{
    int v[G+5][G+5];
    void O() { ms(v, 0); }
    void E() { ms(v, 0); for (int i = 0; i <= G; ++i)v[i][i] = 1; }
    void P()//输出矩阵
    {
        for (int i = 0; i <= G; ++i)
        {
            for (int j = 0; j <= G; ++j)printf("%d ", v[i][j]); puts("");
        }
    }
    MX operator * (const MX &b) const//矩阵乘法
    {
        MX c; c.O();
        for (int k = 0; k <= G; ++k)
        {
            for (int i = 0; i <= G; ++i) if (v[i][k])
            {
                for (int j = 0; j <= G; ++j)
                {
                    c.v[i][j] = (c.v[i][j] + (LL)v[i][k] * b.v[k][j]) % MOD;
                }
            }
        }
        return c;
    }

    MX operator ^ (LL p) const//矩阵快速幂
    {
        MX y; y.E();
        MX x; memcpy(x.v, v, sizeof(v));
        while (p)
        {
            if (p&1) y = y*x;
            x = x*x;
            p>>=1;
        }
        return y;
    }
}a;

int n,t;
char s[N+10][N+10];

int main(){
	#ifdef LOCAL_DEFINE
	    freopen("rush_in.txt", "r", stdin);
	#endif
	ios::sync_with_stdio(0),cin.tie(0);
    cin >> n >> t;
    for (int i = 1;i <= n;i++) cin >> (s[i]+1);
    for (int i = 1;i <= n;i++)
        for (int j = 8;j >= 1;j--)
            a.v[(i-1)*9+j][(i-1)*9+j-1] = 1;
    for (int i = 1;i <= n;i++)
        for (int j = 1;j <= n;j++)
            if (s[i][j]>'0'){
                int x = s[i][j]-'0';
                a.v[(i-1)*9][(j-1)*9+x-1] = 1;
            }
    a = a^(t);
    cout<<a.v[(1-1)*9][(n-1)*9]<<endl;
	return 0;
}

posted @ 2018-05-06 17:15  AWCXV  阅读(112)  评论(0编辑  收藏  举报