Evanyou Blog 彩带

  题目传送门

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


  分析:

  这题的思路其实和[TJOI2017]可乐有些相似。

  如果没有那条不会立刻沿着刚刚走来的路走回的限制,那么就直接邻接矩阵搞一波快速幂就行了。但是加了这条限制之后,我们以点作矩阵的元似乎无从下手,那么不如换一下,把边作为矩阵的元。

  以边作为矩阵的元,那么所求的结果就变成了与起点相连的所有边到达与终点相连的所有边的方案数。构造矩阵的时候我们就可以先用邻接链表存边,把一条无向边拆成两条有向边,然后在构造矩阵的时候用点来连接两条边,并且判断这两条边是否属于同一条无向边,如果是,在构造矩阵的时候就不用把这条边算上。然后就是矩阵加速转移了。

  Code:

  

//It is made by HolseLee on 11th Sep 2018
//Luogu.org P1224
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int mod=45989;
int n,m,t,sta,ed,head[60],cnte,ans;
struct Edge {
    int to,nxt;
    Edge() {}
    Edge(int _x,int _y): to(_x),nxt(_y) {}
}e[201];
struct Matrix {
    int a[150][150],n,m;
    
    Matrix() {memset(a,0,sizeof(a));n=m=0;}
    Matrix(int b[150][150]) {memcpy(a,b,sizeof(a));}

    friend Matrix operator * (const Matrix x,const Matrix y) {
        Matrix ret;
        ret.n=x.n, ret.m=y.m;
        for(int i=1; i<=x.n; ++i)
        for(int j=1; j<=y.m; ++j)
        for(int k=1; k<=x.m; ++k) 
            ret.a[i][j]=(ret.a[i][j]+(x.a[i][k]*y.a[k][j])%mod)%mod;
        return ret; 
    }
}M,T;

inline int read()
{
    char ch=getchar(); int num=0; bool flag=false;
    while( ch<'0' || ch>'9' ) {
        if( ch=='-' ) flag=true; ch=getchar();
    }
    while( ch>='0' && ch<='9' ) {
        num=num*10+ch-'0'; ch=getchar();
    }
    return flag ? -num : num;
}

inline void add(int x,int y)
{
    e[++cnte]=Edge(y,head[x]);
    head[x]=cnte;
}

inline int get(int x)
{
    return (x&1) ? x+1 : x-1;
}

int main()
{
    n=read(); m=read(); t=read()-1;
    sta=read()+1, ed=read()+1; 
    memset(head,-1,sizeof(head));
    int x,y;
    for(int i=1; i<=m; ++i) {
        x=read()+1, y=read()+1;
        add(x,y), add(y,x);
    }
    for(int j=1; j<=cnte; ++j){
        x=e[j].to;
        for(int i=head[x]; i!=-1; i=e[i].nxt) {
            if( i==get(j) ) continue;
            T.a[j][i]++;
        }
    }
    for(int i=head[sta]; i!=-1; i=e[i].nxt) M.a[1][i]++;
    M.n=1, M.m=T.n=T.m=cnte;
    while( t ) {
        if( t&1 ) M=M*T;
        t>>=1, T=T*T;
    }
    for(int i=head[ed]; i!=-1; i=e[i].nxt)
    ans=(ans+M.a[1][get(i)])%mod;
    printf("%d",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/cytus/p/9627435.html