P3758 TJOI2017 可樂
阿新 • • 發佈:2020-07-27
記錄邊權的鄰接矩陣
\(D_{i,j}=+\infty(i=j)||i與j間邊權,i與j聯通,+\infty(i,j不連通)\)
\(D_{(i,j)}^2=min_{i\le k\le n}D_{i,k}+D_{k,j}\)
\(D^K_{i,j}表示i到j經過k條邊的最短路\)
記錄連通性的矩陣意義等價
\(A^k_{i,j}表示由i到j經過k條邊的方案數\)
P3758 TJOI2017 可樂
總方案數=\(t秒後處於各個位置的可能+所有已經爆炸的方案\)
在原先 n 個點的基礎上加一個點 0,表示機器人自爆後的去處,每個點都向 0 連一條單向邊
對於每個點可以新增一個自環,走這個自環就代表停在這裡,那麼每秒就都可以走一步
只需要建出鄰接矩陣,然後矩陣快速冪求出點 1 到每一點的方案數,求和即可
#include<cstdio> #include<cstring> #define mod 2017 #define int long long using namespace std; int answ = 0,n,m; struct mat { int a[101][101]; init(){memset(a,0,sizeof(a));} void qwq(){for(int i=1;i<=n;i++)a[i][i]=1;} }a,ans; mat operator *(const mat &x,const mat &y) { mat z; for(int k=1;k<=n;++k) for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j]%mod)%mod; return z; } signed main(){ scanf("%lld%lld",&n,&m); n++; int x,y,t; for(int i = 1;i <= m;i++){ scanf("%lld%lld",&x,&y); a.a[x][y] = 1; a.a[y][x] = 1; } for(int i=1;i<=n;i++)a.a[i][n]=1,a.a[i][i]=1; ans.init(); scanf("%lld",&t); while(t){ if(t & 1) ans = ans * a; t >>=1; a = a * a; } for(int i = 1;i <= n;i++) answ = (ans.a[1][i] + answ) % mod; printf("%lld",answ); }