bzoj1898: [Zjoi2005]Swamp 沼泽鳄鱼

来源:互联网 发布:淘宝 跑腿 编辑:程序博客网 时间:2024/06/10 10:51

传送门
首先我们发现lcm(2,3,4)=12很小
于是我们预处理出12个时刻内所有合法转移
然后我们大力矩阵乘法就可以了。

#include<cstring>#include<cmath>   #include<cstdio>  #include<iostream>  #include<cstdlib>   #include<algorithm>#define ll long long#define N 50005using namespace std;struct edge{int x,y,z;}e[3005];int n,m,s,t,k,p,fish[25][10];struct matrix{    int a[55][55];    void clear(){memset(a,0,sizeof(a));}    matrix operator * (const matrix b) const    {        matrix c;        c.clear();        for (int i=0;i<n;i++)            for (int j=0;j<n;j++)                for (int k=0;k<n;k++)                    c.a[i][j]=(a[i][k]*b.a[k][j]+c.a[i][j])%10000;        return c;    }    void build(int tim){        clear();        int ok[55];        memset(ok,1,sizeof(ok));         for (int i=1;i<=p;i++) ok[fish[i][tim%fish[i][4]]]=0;        for (int i=1;i<=m;i++){            if (ok[e[i].x]) a[e[i].y][e[i].x]=1;             if (ok[e[i].y]) a[e[i].x][e[i].y]=1;        }    }    matrix pow(int x){        matrix c,d;        c.clear();        memcpy(d.a,a,sizeof(a));        for (int i=0;i<n;i++) c.a[i][i]=1;        while (x){            if (x%2) c=c*d;            d=d*d;            x/=2;        }        return c;    }}ans,ppp[15]; int main(){    scanf("%d%d%d%d%d",&n,&m,&s,&t,&k);    for (int i=1;i<=m;i++) scanf("%d%d",&e[i].x,&e[i].y);    scanf("%d",&p);    for (int i=1;i<=p;i++){        scanf("%d",&fish[i][4]);        for (int j=0;j<fish[i][4];j++) scanf("%d",&fish[i][j]);    }    for (int i=1;i<=12;i++) ppp[i].build(i);    for (int i=0;i<n;i++) ppp[0].a[i][i]=1;    for (int i=1;i<=12;i++) ppp[i]=ppp[i-1]*ppp[i];    ans=ppp[12].pow(k/12)*ppp[k%12];    printf("%d",ans.a[s][t]);}
原创粉丝点击