【题解】 P2151 [SDOI2009]HH去散步

\(Description:\)

给出一张图,求\(A->B\),经过t的时间之后的方案数,答案对45989取模。

但不能\(a->b\),马上,\(b->a\)

\(Sample\) \(Input\):

4 5 3 0 0
0 1
0 2
0 3
2 1
3 2

\(Sample\) \(Output:\)

4

\(Solution:\)

很明显这题是矩乘,但不知道怎么管那个限制条件。

这又是套路题。。。

考虑边是不会走反的,那么把边变成矩阵的点,这样就可以保障不会走反。

那么只有在两条边中一条边的终点为另一条起点时才可以连

然后一开始要强制走到A,做t-1次幂。

再把强制走的矩阵乘上去,最后统计终点为B的边的答案。

#pragma GCC optimize("inline")
#include<cstdio>
#include<iostream>
#include<cstring>
#define int long long 
#define one first
#define two second
using namespace std;
int n,m,t,A,B,En,cnt,ans;
const int N=120*2,p=45989;
pair<int,int> E[N+5];
struct matrix {
    int n,m;
    int a[N+5][N+5];
    inline void clear() { n=m=0;memset(a,0,sizeof(a));}
    inline void set(int nx) { n=m=nx;for(int i=1;i<=nx;++i) a[i][i]=1;}
    inline void write() const{
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j) cout<<a[i][j]<<" ";
            cout<<endl;
        }
        putchar('\n');
    }
    inline matrix operator *  (const matrix &nt) const {
        matrix tmp;tmp.clear();
        tmp.n=n;tmp.m=nt.m;
        for(int i=1;i<=n;++i) for(int j=1;j<=nt.m;++j) for(int k=1;k<=m;++k)
            tmp.a[i][j]=(tmp.a[i][j]+a[i][k]*nt.a[k][j]%p)%p;
        return tmp;
    }
    inline matrix operator *= (const matrix &nt) { return (*this)=(*this)*nt;}
}a,b;
inline matrix power(matrix x,int b){
    matrix ret;ret.clear();
    ret.set(x.n);
    while(b>0){
        if(b&1) ret=ret*x;
        x=x*x;
        b>>=1;
    }
    return ret;
}
signed main(){
    if(fopen("desire.in","r")){
        freopen("desire.in","r",stdin);
        freopen("desire.out","w",stdout);
    }
    ios::sync_with_stdio(0);
    cin>>n>>m>>t>>A>>B;
    for(int i=1;i<=m;++i){
        int u=0,v=0;
        cin>>u>>v;
        E[++En]=make_pair(u,v);
        E[++En]=make_pair(v,u);
    }
    a.n=1;a.m=En;
    b.n=En;b.m=En;
    for(int i=1;i<=En;++i) for(int j=1;j<=En;++j){
        if(((i&1) && i+1==j) || (!(i&1) && i-1==j) || i==j) continue;
        if(E[i].two==E[j].one) b.a[i][j]=1;
    }
        
    for(int i=1;i<=En;++i) if(E[i].one==A) a.a[1][i]=1;
    a=a*power(b,t-1);
    for(int i=1;i<=En;++i) if(E[i].two==B) ans=(ans+a.a[1][i])%p;
    cout<<ans<<endl;
    return 0;
}


转载于:https://www.cnblogs.com/JCNL666/p/10687904.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值