[BZOJ1875/SDOI2009]HH去散步

yingyingying

被Yxm说成SB T_T

这个题非常非常棒!至少我是想不出来点边互化来解决问题。

首先我们可以用点边互化来规避问题。

之后考虑该怎么构造矩阵以及统计答案,

显然要把a->b->c的这两个边在临接矩阵中设为1,

然后用一个虚点向S连边,T向另一个虚点连边。最后统计这两条边的f值即可。


本题巨坑一:“不会立刻沿着刚刚走来的路走回”但可以从重边走回。

本题巨坑二(对本蒟蒻这Linux自带的输入法真TM坑啊):在外面搞好了临接矩阵就不用再在矩阵乘里特判了,即:

for(int i=1;i<=tot;i++)
        {
                for(int j=1;j<=tot;j++)
                {
                        //if(j==(i^1)) continue;
                        for(int k=1;k<=tot;k++)
                        {
                                (ans.f[i][j]+=x.f[i][k]*y.f[k][j]%mod)%=mod;
                        }
                }
        }

否则会使矩阵乘(新定义的)不满足结合率,所以快速幂(醉了这输入法)会出错

 

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define r register 
#define int long long
using namespace std;
const int mod=45989;
int k,s,t,tot,n,m,fr[200],to[200];
struct Ma{int f[200][200];}S;
void add(int x,int y)
{
        fr[++tot]=x;
        to[tot]=y;
}
Ma X(Ma x,Ma y)
{
        Ma ans;
        memset(ans.f,0,sizeof(ans.f));
        for(int i=1;i<=tot;i++)
        {
                ans.f[i][i^1]=0;
        }
        for(int i=1;i<=tot;i++)
        {
                for(int j=1;j<=tot;j++)
                {
                        //if(j==(i^1)) continue;
                        for(int k=1;k<=tot;k++)
                        {
                                (ans.f[i][j]+=x.f[i][k]*y.f[k][j]%mod)%=mod;
                        }
                }
        }
        return ans;
}
Ma poww(Ma x,int y)
{
        Ma ans;
        for(int i=1;i<=tot;i++)
        {
                for(int j=1;j<=tot;j++)
                {
                        ans.f[i][j]=(i==j?1:0);
                }
        }
        while(y)
        {
                if(y&1) ans=X(x,ans);
                y>>=1;
                x=X(x,x);
        }
        return ans;
}
main()
{
        //freopen("1.in","r",stdin);
        scanf("%lld%lld%lld%lld%lld",&n,&m,&k,&s,&t);
        add(n,s);
        for(int i=1,x,y;i<=m;i++)
        {
                scanf("%lld%lld",&x,&y);
                add(x,y); add(y,x);
        }
        add(t,n+1);
        for(int i=1;i<=tot;i++)
        {
                for(int j=1;j<=tot;j++)
                {
                        if(to[i]!=fr[j]) continue;
                        if(i==(j^1)) continue;
                        S.f[i][j]++;
                }
        }
        S=poww(S,k+1);
        printf("%lld",S.f[1][tot]%mod);
        return 0;
}

 

posted @ 2019-07-18 20:26  ATHOSD  阅读(139)  评论(2编辑  收藏  举报