Luogu P3758 可樂
阿新 • • 發佈:2021-01-21
Luogu P3758 可樂
本題是一個經典的矩陣快速冪好題。
但與其他題不一樣的是,這個題的資料範圍給的提示不是特別明顯。其他題,如 POJ3735 中,\(m\leq 10^{10}\),就是一個鮮明的提示。而此題中,\(t\leq 10^6\),不算典型舉證快速冪的資料範圍,但也卡住了普通矩陣連乘的時間複雜度。
從題面中他可以留在原地,或隨機前往一個相鄰的點,這個條件其實可以看出用的是矩陣快速冪(有點像 P6569 [NOI Online #3 提高組] 魔法值),問題就是如何處理自爆。
我們從問題的本質出發來思考這個問題。
自爆,其實就是打斷了他的雙腿,不能再走動了。對啊!我們可以設定一個點 \(n+1\)
如果上述描述有點抽象,我們那樣例賴建一個矩陣,如下:
\[\begin{bmatrix}1&1&0&1\\1&1&1&1\\0&1&1&1\\0&0&0&1\end{bmatrix} \]快速冪計算,最後將第一行的答案累加起來即可。記得取模
//Don't act like a loser. //You can only use the code for studying or finding mistakes //Or,you'll be punished by Sakyamuni!!! #include<iostream> #include<cstdio> #include<cmath> using namespace std; const int MAXN=40,mod=2017; int n,m,t; struct matrix { long long data[MAXN][MAXN]; int col,row; void clear() { col=row=0; for(int i=0;i<MAXN;i++) { for(int j=0;j<MAXN;j++) { data[i][j]=0; } } } void initialize() { clear(); col=row=n+1; for(int i=1;i<=n+1;i++) { data[i][i]=1; } } inline matrix operator *(matrix& b)const { matrix ret; ret.clear(); for(int i=1;i<=col;i++) { for(int k=1;k<=row;k++) { if(data[i][k]==0) continue; for(int j=1;j<=b.row;j++) { ret.data[i][j]+=data[i][k]*b.data[k][j]%mod; ret.data[i][j]%=mod; } } } ret.col=col; ret.row=b.row; return ret; } }; matrix ans; matrix opt; inline void qpow(int y) { while(y) { if(y&1) { ans=ans*opt; } opt=opt*opt; y>>=1; } } signed main() { cin>>n>>m; opt.initialize(); for(int i=1;i<=n;i++) { opt.data[i][n+1]=1; } for(int i=1;i<=m;i++) { int u,v; cin>>u>>v; opt.data[u][v]=opt.data[v][u]=1; } ans.initialize(); opt.col=opt.row=n+1; cin>>t; qpow(t); int tot=0; for(int i=1;i<=n+1;i++) { tot=(tot+ans.data[1][i])%mod; } cout<<tot<<endl; return 0; }