[SDOI2009] HH去散步 (矩阵乘法)

link

$solution:$

将边化为点后重新建矩阵,跑$T-1$幂即可(因为跑的是新边)。

最后直接找与$x,y$所相连的边即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define int long long
#define mod 45989
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
const int MAXN=101;
struct Matrix{
    int a[MAXN<<1][MAXN<<1];
    void init(){memset(a,0,sizeof(a));return;}
}F,G;
int cnt,n,m,A,B,T,sta[MAXN][MAXN<<1],End[MAXN<<1];
Matrix operator*(Matrix x1,Matrix x2){
    Matrix x3;x3.init();
    for(int i=1;i<=(m<<1);i++)
        for(int k=1;k<=(m<<1);k++)
            for(int j=1;j<=(m<<1);j++) x3.a[i][j]+=x1.a[i][k]*x2.a[k][j],x3.a[i][j]%=mod;
    return x3;
}
Matrix ksm(Matrix a,int b){
    Matrix ans;ans.init();
    for(int i=1;i<=(m<<1);i++) ans.a[i][i]=1;
    while(b){
        if(b&1) ans=ans*a;
        a=a*a,b>>=1;
    }return ans;
}int ans;
int uu[MAXN<<1],vv[MAXN<<1];
bool check(int idi,int idj){
    if(vv[idi]==uu[idj]) return 1;
    return 0;
}
signed main(){
    n=read(),m=read(),T=read(),A=read()+1,B=read()+1;
    for(int i=1;i<=m;i++){
        int u=read()+1,v=read()+1;
        if(v==B) End[++End[0]]=i;
        if(u==B) End[++End[0]]=i+m; 
        sta[u][++sta[u][0]]=i;
        uu[i]=u,vv[i]=v;
        sta[v][++sta[v][0]]=i+m;
        uu[i+m]=v,vv[i+m]=u;
    }F.init(),G.init();
    for(int i=1;i<=(m<<1);i++){
        for(int j=1;j<=(m<<1);j++) if(check(i,j)&&(i+m!=j&&j+m!=i)) G.a[i][j]=1;
    }
    //print(G);
    //printf("=========================\n");
    F=ksm(G,T-1);
    //print(F);
    //for(int i=1;i<=End[0];i++) printf("End(%d):%d\n",i,End[i]);
    //for(int i=1;i<=sta[A][0];i++) printf("sta(%d):%d\n",i,sta[A][i]);
    for(int i=1;i<=sta[A][0];i++)
        for(int j=1;j<=End[0];j++) ans+=F.a[sta[A][i]][End[j]],ans%=mod;
    printf("%lld\n",ans); 
}
View Code

 

posted @ 2019-03-26 17:56  siruiyang_sry  阅读(188)  评论(0编辑  收藏  举报