bzoj1875: [SDOI2009]HH去散步

矩阵乘法。

关于点的无法表示刚才走过的路不能走,所以用把边拆成俩个来建图,自己不能和自己连。

然后再用俩点表示起点和终点。

快速幂求矩阵(t+1)次就可以了(t+1次是因为到达终点那条边就需要t次,然后新建了一个终点,就会多走一步)。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 200;
const int maxm = 200;
const int mod = 45989;

int u[maxm],v[maxm],next[maxm],eid;
int n,m,t,p1,p2;

void addedge(int a,int b) {
    u[eid]=a; v[eid]=b; eid++;//next[eid]=g[a]; g[a]=eid++;
    u[eid]=b; v[eid]=a; eid++;//next[eid]=g[b]; g[b]=eid++;
}

struct Matrix {
    int a[maxm][maxm];
    
    int* operator [] (int x) {
        return a[x];
    }
    
    Matrix operator * (Matrix b) {
        Matrix res;
        for(int i=0;i<=n;i++)
        for(int j=0;j<=n;j++)
        for(int k=0;k<=n;k++)
            res[i][k]=(res[i][k]+a[i][j]*b[j][k])%mod;
        return res;
    }
    
    Matrix operator ^ (int e) {
        Matrix res,tmp=*this;
        res.init();
        while(e) {
            if(e&1) res=res*tmp;
            tmp=tmp*tmp;
            e>>=1;
        }
        return res;
    }
    
    void init() {
        memset(a,0,sizeof(a));    
        for(int i=0;i<=n;i++) a[i][i]=1;
    }
    
    void debug() {
        for(int i=0;i<=n;i++) {
            for(int j=0;j<=n;j++) printf("%d ",a[i][j]);
            printf("\n");    
        }
        
    }
    
    Matrix() {
        memset(a,0,sizeof(a));    
    }
}s;

int main() {
    scanf("%d%d%d%d%d",&n,&m,&t,&p1,&p2);
    
    for(int i=1,u,v;i<=m;i++) {
        scanf("%d%d",&u,&v);
        addedge(u,v);
    }
    
    for(int i=0;i<eid;i++)
    for(int j=0;j<eid;j++) 
        if(v[i]==u[j]&& (i!=(j^1))) {
            s[i][j]=1;        
            
    }
    for(int i=0;i<eid;i++) {
        if(u[i]==p1) s[eid][i]=1;
        if(v[i]==p2) s[i][eid+1]=1;        
    }
    n=eid+1;
    s=s^(t+1);
    printf("%d\n",s[eid][eid+1]);
    return 0;
}
posted @ 2016-07-16 19:40  invoid  阅读(275)  评论(0编辑  收藏  举报