P3758 [TJOI2017]可樂
阿新 • • 發佈:2021-06-10
原題連結
考察:矩陣快速冪
思路:
想了dp轉移方程,看了題解發現沒有這麼複雜,利用鄰接矩陣的性質就行了,參考Floyd演算法,外層每迴圈一次,相當於經過了一條邊,也是轉移到了一個新的狀態.
把停留看成自環,城市之間的道路就等同於鄰接矩陣的原本意義,但是爆炸就比較難處理.大佬的思路是建立虛點,該點只有入度沒有出度.那麼每進行一次floyd就相當於進行狀態轉移.但是t太大了,所以進行矩陣加速.
但是注意如果虛點0-->0 的權值為0的話,就會發現爆棧的方案數無法傳遞,所以賦值1.
Code
#include <iostream> #include <cstring> using namespace std; typedef long long LL; const int N = 35,M = 2017; int n,m,T,g[N][N],f[N]; void mul(int f[],int a[][N]) { int res[N] = {0}; for(int i=0;i<N;i++) for(int j=0;j<N;j++) res[i] = (res[i]+(LL)f[j]*a[j][i])%M; memcpy(f,res,sizeof res); } void mul(int a[][N]) { int res[N][N] = {0}; for(int i=0;i<N;i++) for(int j=0;j<N;j++) for(int k=0;k<N;k++) res[i][j] = (res[i][j]+(LL)a[i][k]*a[k][j])%M; memcpy(a,res,sizeof res); } int main() { scanf("%d%d",&n,&m);//爆炸的方案數需要傳遞 for(int i=0;i<=n;i++) g[i][0] = g[i][i] =1; while(m--) { int x,y; scanf("%d%d",&x,&y); g[x][y] = g[y][x] = 1; } f[1] = 1; scanf("%d",&T); while(T) { if(T&1) mul(f,g); mul(g); T>>=1; } int ans = 0; for(int i=0;i<=n;i++) ans+=f[i],ans%=M; printf("%d\n",ans); return 0; }