BZOJ 1875 SDOI2009 HH去散步

1875: [SDOI2009]HH去散步

Time Limit: 20 Sec  Memory Limit: 64 MB
Submit: 2018  Solved: 994
[Submit][Status][Discuss]

Description

HH有个一成不变的习惯,喜欢饭后百步走。所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离。 但
是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回。 又因为HH是个喜欢变化的人,所以他每
天走过的路径都不完全一样,他想知道他究竟有多 少种散步的方法。 现在给你学校的地图(假设每条路的长度都
是一样的都是1),问长度为t,从给定地 点A走到给定地点B共有多少条符合条件的路径

Input

第一行:五个整数N,M,t,A,B。
N表示学校里的路口的个数
M表示学校里的 路的条数
t表示HH想要散步的距离
A表示散步的出发点
B则表示散步的终点。
接下来M行
每行一组Ai,Bi,表示从路口Ai到路口Bi有一条路。
数据保证Ai != Bi,但不保证任意两个路口之间至多只有一条路相连接。 
路口编号从0到N -1。 
同一行内所有数据均由一个空格隔开,行首行尾没有多余空格。没有多余空行。 
答案模45989。
N ≤ 20,M ≤ 60,t ≤ 2^30,0 ≤ A,B

Output

一行,表示答案。

Sample Input

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

Sample Output

4

HINT

Source

显然需要搞出个矩阵之后矩乘。 
然而这题的要求就很烦,要不然就是SB题了2333. 
但是我们可以换一个想法来做。 
题目要求不走上一条来的边,况且边的数量还很少,所以我们可以考虑将矩阵构造成从一条边走到另一条边的方案数。 
这样的话我们避免走上一条来的路就很简单的能判断了。 
构造出初始矩阵后,我们求该矩阵的t-1次方。 
然后再用起点走一步能到的边的矩阵乘以该矩阵。 
之后起点到链接终点的边的所有方案数之和即为答案。

注意矩阵乘法不满足交换律

#include <bits/stdc++.h>
#define ll long long 
using namespace std;
inline int read(){
    int x=0;int f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int MOD=45989;
const int MAXN=10000;
namespace zhangenming{
    struct node{
        int x,y;
    }e[MAXN];
    struct Martrix{
        int martrix[130][130];
    }ans,x,st;
    int n,m,A,B,t,M,anss[MAXN],ans_top=0;
    void init(){
        n=read();m=read();t=read();A=read();B=read();
        for(int i=1;i<=m;i++){
            e[i].x=read();
            e[i].y=read();
            if(e[i].x==B) anss[++ans_top]=i+m;
            if(e[i].y==B) anss[++ans_top]=i;
        }
        for(int i=1;i<=m;i++){
            for(int j=1;j<=m;j++){
                if(i==j) continue;
                if(e[i].y==e[j].x) x.martrix[i][j]=1;
                if(e[i].x==e[j].x) x.martrix[i+m][j]=1;
                if(e[i].y==e[j].y) x.martrix[i][j+m]=1;
                if(e[i].x==e[j].y) x.martrix[i+m][j+m]=1;
            }
            if(e[i].x==A) st.martrix[1][i]=1;
            if(e[i].y==A) st.martrix[1][i+m]=1;
        }
    }
    void operator *= (Martrix &x,Martrix y){
        Martrix z;
        memset(&z,0,sizeof(z));
        for(int i=1;i<=M;i++){
            for(int j=1;j<=M;j++){
                for(int k=1;k<=M;k++){
                    z.martrix[i][j]+=x.martrix[i][k]*y.martrix[k][j];
                    z.martrix[i][j]%=MOD;
                }
            }
        }
        x=z;
    }
    void print(Martrix &a){
        for(int i=1;i<=M;i++){
            for(int j=1;j<=M;j++){
                cout<<a.martrix[i][j]<<' ';
            }
            cout<<endl;
        }
        cout<<endl;
    }
    void ksm(int k){
        while(k){
            if(k&1) ans*=x;
            x*=x;
            k>>=1; 
        }
         st*=ans;
    }
    void solve(){
        M=m+m;
        for(int i=1;i<=M;i++){
            ans.martrix[i][i]=1;
        }
        ksm(t-1);
        ll tot=0;
        for(int i=1;i<=ans_top;i++){
            tot+=st.martrix[1][anss[i]];
            tot%=MOD;
        }
        cout<<tot<<endl;
    }
}
int main(){
    using namespace zhangenming;
    init();
    solve();
    return 0;
}

  

 

posted @ 2017-12-25 10:38  zhangenming  阅读(156)  评论(0编辑  收藏  举报