【矩陣】BZOJ 1875 || SDOI 2009 HH去散步

菜雞湯發表於2014-12-13

一眼就能看出的矩陣加速,但是需要進行轉換,主要在於題目中的不能馬上走剛剛通過的路,所以有特殊的處理,無向邊變有向邊,邊變點做矩陣加速。

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#define MAXN 400
const int mod = 45989;
using namespace std;
int N,M,T,A,B;
struct mat{
    int n,m;
    int t[MAXN +10][MAXN +10];
    void init_min(){memset(t,0,sizeof(t));}
    void init_max(){memset(t,0x3f,sizeof(t));}
    void init_e()
    {
        memset(t,0,sizeof(t));
        for(int i = 0;i < MAXN;i++)
            t[i][i] = 1;
    }
    mat operator *(const mat &a) 
    {
        mat c;
        c.init_min();
        c.n = n;
        c.m = a.m;
        for(int i = 0;i < n;i++)
            for(int j = 0;j < a.n;j++)
                for(int k = 0;k < a.m;k++)
                    c.t[i][k] = (c.t[i][k] + t[i][j] * a.t[j][k]) % mod;
        return c;
    }
};
mat map;
mat pow(mat a,int k)
{
    mat ans;
    ans.init_e();
    ans.n = a.n;
    ans.m = a.m;
    while(k)
    {
        if(k&1)
            ans = ans * a;
        a = a * a;
        k >>= 1;
         
    }
    return ans;
}
vector<pair<int,int> >Edges;
void pre()//邊連邊的初始化處理
{
    int i,j;
    for(i = 0; i < Edges.size(); i++) 
        for(j = 0; j < Edges.size(); j++)
            if(Edges[i].second == Edges[j].first && (j ^ 1) != i)
                map.t[i][j]++;
}
int main()
{
    int i,j,k;
    int u,v;
    scanf("%d%d%d%d%d",&N,&M,&T,&A,&B);
    for(i = 0;i < M;i++){
        scanf("%d%d",&u,&v);
        Edges.push_back(make_pair(u, v));
        Edges.push_back(make_pair(v, u));
    }
    pre();
    map.n = map.m = M * 2;
    mat tt;
    tt = pow(map,T - 1);
    int ans = 0;
    for(int i = 0; i < Edges.size(); i++)   if(Edges[i].first == A)
    for(int j = 0; j < Edges.size(); j++)   if(Edges[j].second == B)
        ans = (ans + tt.t[i][j]) % mod;
    printf("%d\n",ans);
}


相關文章