bzoj1875 边点互换+矩乘

https://www.lydsy.com/JudgeOnline/problem.php?id=1875

题意 HH有个一成不变的习惯,喜欢饭后百步走。所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离。 但

是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回。 又因为HH是个喜欢变化的人,所以他每
天走过的路径都不完全一样,他想知道他究竟有多 少种散步的方法。 现在给你学校的地图(假设每条路的长度都
是一样的都是1),问长度为t,从给定地 点A走到给定地点B共有多少条符合条件的路径
 
开始没有看到不能走回头路的条件,以为是道人尽皆知傻逼矩阵快速幂,WA了好几发后才发现这个奇形怪状的条件。
既然不能走回头路,我们就不能用点构造矩阵了,考虑直接用边来构造矩阵,表示边与边之间到达的关系。
dp[i][j]表示边i通过k次操作到达边j的数目。
我们建立两个虚点,一个x指向所有起点为S的边,一个y被所有终点为T的边指向,最终x需要经过K + 1条边到达y的数目即为答案
构造矩阵即可。
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)  
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))  
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Scl(x) scanf("%lld",&x);  
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);  
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long  
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second 
typedef vector<int> VI;
const double eps = 1e-9;
const int maxn = 125;
const int INF = 0x3f3f3f3f;
const int mod = 45989; 
int N,M,tmp,K,tot; 
int S,T;
struct Mat{
    LL a[maxn][maxn];
    void init(){
        Mem(a,0);
    }
}base;
struct Edge{
    int u,v;
    Edge(int u = 0,int v = 0):u(u),v(v) {}
}edge[maxn];
Mat operator * (Mat a,Mat b){
    Mat ans; ans.init();
    for(int i = 0 ; i <= tot ; i ++){
        for(int j = 0 ; j <= tot; j ++){
            for(int k = 0; k <= tot; k ++){
                ans.a[i][j] = (ans.a[i][j] + a.a[i][k] * b.a[k][j]) % mod;
            }
        }
    }
    return ans;
}
Mat operator ^ (Mat a,int b){
    Mat x,y = a;
    x.init();
    For(i,0,tot) x.a[i][i] = 1;
    while(b){
        if(b & 1) x = x * y;
        b >>= 1;
        y = y * y;
    }
    return x;
}
void solve(){
    base = base ^ (K + 1);
    printf("%lld",base.a[0][1]);
}
int main()
{
    scanf("%d%d%d%d%d",&N,&M,&K,&S,&T);
    base.init(); tot = 2;
    For(i,1,M){
        int u,v; Sca2(u,v);
        edge[tot++] = Edge(u,v);
        edge[tot++] = Edge(v,u); 
    }
    tot--;
    For(i,2,tot){
        if(edge[i].u == S) base.a[0][i] = 1;
        if(edge[i].v == T) base.a[i][1] = 1;
        For(j,2,tot){
            if(edge[i].v == edge[j].u && (i ^ j ) != 1) base.a[i][j] = 1;
        }
    }
    solve();
    #ifdef VSCode
    system("pause");
    #endif
    return 0;
}

 

posted @ 2018-09-24 21:44  Hugh_Locke  阅读(348)  评论(0编辑  收藏  举报