BZOJ 1875: [SDOI2009]HH去散步(矩阵乘法)

首先,题意就把我们引向了矩阵乘法,注意边长m<=60,那么就按边建图,变成一个120个点的图,然后乱搞就行了。

PS:WA了N久改了3次终于A了QAQ

CODE:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define mod 45989
using namespace std;
struct mat{
    int n,m;
    long long a[122][122];
    mat(){n=m=0;memset(a,0,sizeof(a));}
    int I(int _x){n=m=_x;for (int i=1;i<=n;i++) a[i][i]=1;}
};
mat operator *(const mat x,const mat y){
    mat ans;
    ans.n=x.n;ans.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++)
                (ans.a[i][j]+=x.a[i][k]*y.a[k][j])%=mod;
    return ans;
}
mat power(mat x,long long y){
    mat ans;ans.I(x.n);
    for (;y;y>>=1){
        if (y&1) ans=ans*x;
        x=x*x;
    }
    return ans;
}
struct edges{
    int id,to,next;
}edge[123];
int l,next[23];
int addedge(int from,int to,int id){
    edge[++l]=(edges){id,to,next[from]};
    next[from]=l;
}
int main(){
    int n,m,a,b;
    long long t;
    mat x;
    scanf("%d%d%lld%d%d",&n,&m,&t,&a,&b);
    x.n=x.m=m*2;
    a++;b++;
    for (int i=1;i<=m;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        x++;y++;
        addedge(x,y,i);
        addedge(y,x,i+m);
    }
    for (int i=1;i<=n;i++)
        for (int j=next[i];j;j=edge[j].next)
            for (int k=next[edge[j].to];k;k=edge[k].next)
                if (abs(edge[j].id-edge[k].id)!=m) x.a[edge[j].id][edge[k].id]=1;
    x=power(x,t-1);
    int q=t&1==1?1:0;
    long long ans=0;
    for (int i=next[a];i;i=edge[i].next)
        for(int j=1;j<=l;j++) if (edge[j].to==b) (ans+=x.a[edge[i].id][edge[j].id])%=mod;
    printf("%lld",ans);
    return 0;
}

 

posted @ 2014-06-15 17:03  New_Godess  阅读(145)  评论(0编辑  收藏  举报