题目链接:传送门
题意:
一个图有n个顶点。已知邻接矩阵。问点能够反复用长度小于m的路径有多少。
分析:
首先我们知道了邻接矩阵A。那么A^k代表的就是长度为k的路径有多少个。
那么结果就是A^0+A^1+A^2+...+A^m。
然后我们能够构造一个矩阵来帮助我们求解。
X = | A , E |
| 0 , E |
==> 然后X^m 的矩阵的右上角的矩阵代表的就是A^0+A^1+A^2+...+A^m。
当然A^0+A^1+A^2+...+A^m,也能够用二分来求。
代码例如以下:
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; const int maxn = 51*2; const int mod = 2015; typedef long long LL; struct matrix{ int a[maxn][maxn]; matrix(){ memset(a,0,sizeof(a)); } }; matrix I; void init(){ for(int i=0;i<maxn;i++) I.a[i][i]=1; } int n,m; matrix multi(matrix A,matrix B){ matrix C; for(int i=0;i<2*n;i++){ for(int j=0;j<2*n;j++){ for(int k=0;k<2*n;k++){ C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j]); } C.a[i][j]%=mod; } } return C; } matrix add(matrix A,matrix B){ matrix C; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ C.a[i][j]=(A.a[i][j]+B.a[i][j])%mod; } } return C; } int quick_mod(matrix A,int b){ matrix ans = I; while(b){ if(b&1) ans = multi(ans,A); b>>=1; A=multi(A,A); } int sum = 0; for(int i=0;i<n;i++){ for(int j=n;j<n*2;j++) sum=sum+ans.a[i][j]; } // cout<<"----------ans------------"<<endl; // for(int i=0;i<2*n;i++){ // for(int j=0;j<2*n;j++) // cout<<ans.a[i][j]<<" "; // cout<<endl; // } // cout<<"----------ans------------"<<endl; return sum%mod; } int main() { init(); int t; scanf("%d",&t); while(t--){ scanf("%d%d",&n,&m); matrix A,B; for(int i=0;i<n;i++){ int k,u; scanf("%d",&k); while(k--){ scanf("%d",&u); A.a[i][--u]=1; } } for(int i=0;i<n;i++) A.a[i][i+n]=1; for(int i=n;i<2*n;i++) A.a[i][i]=1; // cout<<"----------A------------"<<endl; // for(int i=0;i<2*n;i++){ // for(int j=0;j<2*n;j++) // cout<<A.a[i][j]<<" "; // cout<<endl; // } // cout<<"----------A------------"<<endl; int sum = quick_mod(A,m); printf("%d\n",sum+1); } return 0; }