Brief description :
给定一个可能重边但没有自环的无向图,要求计算 A, B 两点之间步数为 t 的方案数。答案模 45989。
(可以经过某个点某条边多次,但是不可以立即沿着同一条边折返。)
(.. N <= 20, M <= 60, t <= 2^30 ..)
Analyse :
由于“不会沿着同一条边折返”,因此从 A 点经过 k 步後的状态仅与最后一步所走的边和它的方向有关。
如果将每条无向边拆成两条有向边,那么仅于边有关。
用 i==(j^1),排除立即走回边。
比如: 2 0010(u1->v1) 4 0100(u2->v2)
3 0011(v1->u1) 5 0101(v2->u2)
----> (2&1)==3 (3&1)==2 ----> (4&1)==5 (5&1)==4
友链:http://www.shuizilong.com/house/archives/sdoi-2009-hh%E5%8E%BB%E6%95%A3%E6%AD%A5/
CODE:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<string> #include<queue> #include<deque> #include<stack> #include<map> #include<set> #define INF 0x7fffffff #define SUP 0x80000000 #define _p 45989 #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long LL; const int N=100007; struct Edge{ //邻接表节点 int to,next; }E[133]; int head[55]; int tot=2; void add_(int u,int v) { E[tot].to=v; E[tot].next=head[u]; head[u]=tot++; } struct Matrix{ int mat[133][133]; Matrix() { mem(mat,0); } friend Matrix operator *(Matrix a,Matrix b) //非成员函数重载 { Matrix ans; for(int i=1;i<=tot;i++) { for(int j=1;j<=tot;j++) { for(int k=1;k<=tot;k++) ans.mat[i][j]+=a.mat[i][k]*b.mat[k][j]%_p,ans.mat[i][j]%=_p; } } return ans; } friend Matrix operator^(Matrix a,int b) { Matrix ans; for(int i=1;i<=tot;i++) ans.mat[i][i]=1; while(b) { if(b&1) ans=ans*a; //出去回边 a=a*a; b>>=1; } return ans; } }; int main() { int n,m,t,a,b; while(scanf("%d%d%d%d%d",&n,&m,&t,&a,&b)==5) { mem(head,-1); int u,v; for(int i=1;i<=m;i++) { scanf("%d%d",&u,&v); add_(u,v); add_(v,u); } Matrix st,tt; for(int i=head[a];i!=-1;i=E[i].next) st.mat[1][i]=1; //初始的一步 vector<int> en; for(int i=2;i<tot;i++) //转移的矩阵 { int to=E[i].to; if(to==b) en.push_back(i); for(int j=head[to];j!=-1;j=E[j].next) { if(i==(j^1)) continue; tt.mat[i][j]=1; } } int ans=0; st=st*(tt^(t-1)); // 1+(t-1)==t步 ,即初始一步+转移t-1次 for(int i=0;i<en.size();i++) { ans=(ans+st.mat[1][en[i]])%_p; } printf("%d\n",ans); } return 0; }
时间: 2024-10-06 00:53:47