BZOJ 1297 [SCOI2009]迷路 递推 矩阵乘法

题目大意:有向图有 n(n<=10) 个节点,有若干条有向边,经过一条边需要花费一些时间。从节点 0 出发,必须恰好在 T(T<=1000000000) 时刻到达节点 N-1。 总共有多少种不同的路径? 注意:不能在某个节点逗留,且通过某有向边的时间严格为给定的时间。

若知道第i秒的方案,可以推出后面10秒内的部分方案。设第i秒的经过节点j的方案数为f(i,j),则f(i,j)=sigma{f(i-k,t)} ,其中t到j有一条需要消耗k个单位时间的单向边。很明显的递推,可是T很大,想到用矩阵快速幂加速递推。

定义方案矩阵mat为第i秒的经过各点的方案数,可是递推时会可能会更新后10秒的状态,而一个矩阵只能代表1秒。这里采用将一个点分裂成10个点的方法,第一个点代表第i秒经过节点j的方案数,另外9个点为临时存储方案的点,表示从j出发已经走了k秒。
例如从j到t需要x秒,已知i-1秒的状态想求第i秒的状态,那么第i秒经过节点t的方案中就有一部分是在i-1秒时从节点j已经走了x-1秒的方案。以此类推,详见代码。

#include <cstdio>]
#include <cstring>
#define N 100
#define MOD 2009
using namespace std;
struct Matrix {
    int a[N+5][N+5];
    Matrix() { memset(a,0,sizeof a); }
    Matrix operator * (const Matrix& rhs) const {
        Matrix tmp;
        for(int i=0;i<100;i++)
            for(int j=0;j<100;j++)
                for(int k=0;k<100;k++)
                    (tmp.a[i][j]+=a[i][k]*rhs.a[k][j])%=MOD;
        return tmp;
    }
}mat,ini,trans;
Matrix f_pow(Matrix x,int y) {
    Matrix tmp=ini;
    while(y) {
        if(y&1) tmp=tmp*x;
        x=x*x;
        y>>=1;
    }
    return tmp;
}
char a[15][15];
int main() {
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++) scanf("%s",a[i]);
    for(int i=0;i<n;i++)
        for(int j=1;j<10;j++)
            trans.a[i*10+j-1][i*10+j]=1;
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++) {
            int x=a[i][j]-'0';
            if(!x) continue;
            trans.a[i*10+x-1][j*10]=1;
        }
    for(int i=0;i<100;i++) ini.a[i][i]=1;
    mat.a[0][0]=1;
    mat=mat*f_pow(trans,m);
    printf("%d\n",mat.a[0][(n-1)*10]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值