Evanyou Blog 彩带

P2151 [SDOI2009]HH去散步

题目描述

HH有个一成不变的习惯,喜欢饭后百步走。所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离。 但是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回。 又因为HH是个喜欢变化的人,所以他每天走过的路径都不完全一样,他想知道他究竟有多 少种散步的方法。

现在给你学校的地图(假设每条路的长度都是一样的都是1),问长度为t,从给定地 点A走到给定地点B共有多少条符合条件的路径

输入输出格式

输入格式:

第一行:五个整数N,M,t,A,B。其中N表示学校里的路口的个数,M表示学校里的 路的条数,t表示HH想要散步的距离,A表示散步的出发点,而B则表示散步的终点。

接下来M行,每行一组Ai,Bi,表示从路口Ai到路口Bi有一条路。数据保证Ai != Bi,但 不保证任意两个路口之间至多只有一条路相连接。 路口编号从0到N − 1。 同一行内所有数据均由一个空格隔开,行首行尾没有多余空格。没有多余空行。 答案模45989。

输出格式:

一行,表示答案。

输入输出样例

输入样例#1: 
4 5 3 0 0
0 1
0 2
0 3
2 1
3 2
输出样例#1: 
4

说明

对于30%的数据,N ≤ 4,M ≤ 10,t ≤ 10。

对于100%的数据,N ≤ 50,M ≤ 60,t ≤ 2^30,0 ≤ A,B

 

Solution:

  本题矩阵加速dp。

  一眼想到dp,因为刚走过的边不能立即返回,若按点去定义状态就会不好判断重边和刚走过的边的情况,解决办法是按边去定义状态,先把无向边拆成有向边,设$f[i][j]$表示到了第$i$条边走了$j$距离的方案数,于是$f[i][j]=\sum f[k][j-1]$(其中第$k$条边能到第$i$条边,且$i,k$不是同属一条无向边)。

  于是就能矩阵优化dp了,初始矩阵就是个$1*2m$的矩阵,其中是$A$的出边都标记为1,然后转移矩阵是$2m*2m$的矩阵,由入边$i$向出边$j$转移,所以使得$matrix[i][j]++$即可。

  最后答案就统计到达$B$的入边的方案数之和就好了。

代码:

/*Code by 520 -- 9.11*/
#include<bits/stdc++.h>
#define il inline
#define ll long long
#define RE register
#define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
#define Clr(p) memset(&p,0,sizeof(p))
using namespace std;
const int mod=45989;
int n,m,t,A,B,to[130],net[130],h[130],cnt=1;
struct matrix{int a[130][130],r,c;};

il matrix Mul(matrix x,matrix y){
    matrix tp; Clr(tp);
    tp.r=x.r,tp.c=y.c;
    For(i,0,x.r) For(j,0,y.c) For(k,0,x.c)
        tp.a[i][j]=(tp.a[i][j]+x.a[i][k]*y.a[k][j]%mod)%mod;
    return tp;
}

il void solve(int k){
    matrix tp,ans; Clr(tp),Clr(ans);
    ans.r=0,ans.c=tp.r=tp.c=cnt;
    for(RE int i=h[A];i;i=net[i]) ans.a[0][i]=1;
    For(u,0,n-1) for(RE int i=h[u];i;i=net[i]) {
        RE int v=to[i];
        for(RE int j=h[v];j;j=net[j])
            if((j^1)!=i) tp.a[i][j]++;
    }
    while(k){
        if(k&1) ans=Mul(ans,tp);
        k>>=1;
        tp=Mul(tp,tp);
    }
    int tot=0;
    for(RE int i=h[B];i;i=net[i]) tot+=ans.a[0][(i^1)];
    cout<<tot%mod;
}

il void add(int u,int v){to[++cnt]=v,net[cnt]=h[u],h[u]=cnt;}

int main(){
    ios::sync_with_stdio(0);
    cin>>n>>m>>t>>A>>B;
    int u,v;
    For(i,1,m) cin>>u>>v,add(u,v),add(v,u);
    solve(t-1);
    return 0;
}

 

posted @ 2018-09-12 11:01  five20  阅读(128)  评论(0编辑  收藏  举报
Live2D