bzoj1875 [SDOI2009]HH去散步——矩阵快速幂

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1875

有个限制是不能走回头路,比较麻烦;

所以把矩阵中的元素设成边的经过次数,单向边之间就好转移了;

最后从单向边的经过次数得到点的路径方案数。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int const mod=45989;
int n,m,T,A,B,head[25],ct=1,tot;
struct N{
    int hd,to,next;
    N(int h=0,int t=0,int n=0):hd(h),to(t),next(n) {}
}edge[125];
struct Matrix{
    int a[125][125];
    Matrix(){memset(a,0,sizeof a);}//
    Matrix operator * (const Matrix &y) const
    {
        Matrix x;
        for(int i=1;i<=ct;i++)
            for(int k=1;k<=ct;k++)
                for(int j=1;j<=ct;j++)
                    (x.a[i][j]+=a[i][k]*y.a[k][j])%=mod;
        return x;
    }
    void init()
    {
        for(int i=1;i<=ct;i++)a[i][i]=1;
    }
}tr,ans;
Matrix operator ^ (Matrix x,int y)
{
    Matrix ret; ret.init();
    for(int i=y;i;i>>=1,x=x*x)
        if(i&1)ret=ret*x;//i 而不是 y!!!
    return ret;
}
void add(int x,int y){edge[++ct]=N(x,y,head[x]); head[x]=ct;}
int main()
{
    scanf("%d%d%d%d%d",&n,&m,&T,&A,&B);
    for(int i=1,x,y;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y); add(y,x);
    }
    for(int i=head[A];i;i=edge[i].next) ans.a[1][i]++;
    for(int i=2;i<=ct;i++)//2
        for(int j=2;j<=ct;j++)    
            if(edge[i].to==edge[j].hd && i!=(j^1)) tr.a[i][j]++;//
    ans=ans*(tr^(T-1));
    for(int i=head[B];i;i=edge[i].next)
        (tot+=ans.a[1][i^1])%=mod;
    printf("%d",tot);
    return 0;
}

 

posted @ 2018-06-30 15:30  Zinn  阅读(146)  评论(0编辑  收藏  举报