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

安稳与你 提交于 2020-03-05 08:24:47

 [SDOI2009]HH去散步(luogu)

Solution

考虑dp,设计状态 f[i][j] 为当前从起点走了 i 步,到达 j 点

但要避免走上一条走过的路,所以还要记录上一条走过的路是哪一条

可以将 f[i][j] 改为表示当前从起点走了 i 步,在编号为 j 的有向路的终点

转移为f[i][j]=$\Sigma$f[i-1][k] (编号为 k 的有向路的终点是 j 的起点,且不是 j 的反边)

发现 t 过大,不过对于一个 j ,能转移到它的 k 是固定的

于是可以矩阵乘法

Code

 

#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
const int N=51,M=121,P=45989;
int head[N],nxt[M],ver[M],tot;
int n,m,t,a,b,u,v,ans[M][M],pre[M][M],now[M][M];
void mul1()
{
    memset(now,0,sizeof(now));
    for(int i=1;i<=tot;i++)
        for(int j=1;j<=tot;j++)
            for(int k=1;k<=tot;k++)
                now[i][j]+=ans[i][k]*pre[k][j]%P,now[i][j]%=P;
    for(int i=1;i<=tot;i++)
        for(int j=1;j<=tot;j++)
            ans[i][j]=now[i][j];
}
void mul2()
{
    memset(now,0,sizeof(now));
    for(int i=1;i<=tot;i++)
        for(int j=1;j<=tot;j++)
            for(int k=1;k<=tot;k++)
                now[i][j]+=pre[i][k]*pre[k][j]%P,now[i][j]%=P;
    for(int i=1;i<=tot;i++)
        for(int j=1;j<=tot;j++)
            pre[i][j]=now[i][j];
}
void qpow(int y)
{
    while(y)
    {
        if(y&1) mul1();
        mul2(),y>>=1;
    }
}
void add(int x,int y)
{
    ver[++tot]=y,nxt[tot]=head[x],head[x]=tot;
    ver[++tot]=x,nxt[tot]=head[y],head[y]=tot;
}
int op(int x)
{
    return x%2?x+1:x-1;
}
inline char get()
{
    static char buf[1024];
    static int pos=0,size=0;
    if(pos==size)
    {
        size=fread(buf,1,1024,stdin);
        pos=0;
        if(!size) return EOF;
        else return buf[pos++];
    }
    else return buf[pos++];     
}
int read()
{
    int sum=0,fh=1;
    char ch=get();
    while(!(ch>='0' && ch<='9'))
    {
        if(ch=='-') fh=-1;
        ch=get();
    }
    while(ch>='0' && ch<='9' && ch!=EOF) sum=sum*10+ch-48,ch=get();
    return sum*fh;
}
int main()
{
    n=read(),m=read(),t=read(),a=read(),b=read();
    for(int i=1;i<=m;i++)
    {
        u=read(),v=read();
        add(u,v);
    }
    for(int j=1;j<=tot;j++)
        for(int i=head[ver[op(j)]];i;i=nxt[i])
            if(i!=j) pre[op(i)][j]++;
    for(int i=head[a];i;i=nxt[i])
        ans[1][i]++;
    qpow(t-1);
    int an=0;
    for(int i=head[b];i;i=nxt[i])
        an+=ans[1][op(i)],an%=P;
    printf("%d\n",an);
    return 0;
}

 

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!