BZOJ1297 [SCOI2009]迷路 【矩陣優化dp】
阿新 • • 發佈:2018-04-19
return 必須 pan 但是 stream names mem urn cout
題目
windy在有向圖中迷路了。 該有向圖有 N 個節點,windy從節點 0 出發,他必須恰好在 T 時刻到達節點 N-1。 現在給出該有向圖,你能告訴windy總共有多少種不同的路徑嗎? 註意:windy不能在某個節點逗留,且通過某有向邊的時間嚴格為給定的時間。
輸入格式
第一行包含兩個整數,N T。 接下來有 N 行,每行一個長度為 N 的字符串。 第i行第j列為‘0‘表示從節點i到節點j沒有邊。 為‘1‘到‘9‘表示從節點i到節點j需要耗費的時間。
輸出格式
包含一個整數,可能的路徑數,這個數可能很大,只需輸出這個數除以2009的余數。
輸入樣例
5 30
12045
07105
47805
12024
12345
輸出樣例
852
提示
30%的數據,滿足 2 <= N <= 5 ; 1 <= T <= 30 。 100%的數據,滿足 2 <= N <= 10 ; 1 <= T <= 1000000000 。
題解
設\(f[i][t]\)表示\(t\)時刻到達\(i\)號點的方案數
那麽有
\[f[i][t] = \sum\limits_{e(j,i) \in edge} f[j][t - e.w]\]
\(T\)很大,而且顯然這是一個齊次式,考慮矩陣優化
但是矩陣優化只能一層層遞推,這裏邊權的限制使我們可能跨多層
發現邊權很小,考慮拆點
每個點拆成一長條鏈,分別管轄各種權值的出邊
這樣就可以矩陣優化了
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<‘ ‘; puts("");
using namespace std;
const int maxn = 95,maxm = 100005,INF = 1000000000,P = 2009;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == ‘-‘) flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
struct Matrix{
int s[maxn][maxn],n,m;
Matrix(){n = m = 0; memset(s,0,sizeof(s));}
}F,A;
inline Matrix operator *(const Matrix& a,const Matrix& b){
Matrix ans;
if (a.m != b.n) return ans;
ans.n = a.n; ans.m = b.m;
for (int i = 1; i <= ans.n; i++)
for (int j = 1; j <= ans.m; j++)
for (int k = 1; k <= a.m; k++)
ans.s[i][j] = (ans.s[i][j] + a.s[i][k] * b.s[k][j] % P) % P;
return ans;
}
inline Matrix operator ^(Matrix a,int b){
Matrix ans; ans.n = ans.m = a.n;
REP(i,ans.n) ans.s[i][i] = 1;
for (; b; b >>= 1,a = a * a)
if (b & 1) ans = ans * a;
return ans;
}
int n,T;
char s[maxn];
int main(){
n = read(); T = read();
A.n = A.m = 9 * n;
REP(i,n){
scanf("%s",s + 1);
REP(j,n){
if (s[j] != ‘0‘){
int d = s[j] - ‘0‘;
A.s[(j - 1) * 9 + 1][(i - 1) * 9 + d] = 1;
}
}
for (int j = 2; j <= 9; j++)
A.s[(i - 1) * 9 + j][(i - 1) * 9 + j - 1] = 1;
}
F.n = 9 * n; F.m = 1;
F.s[1][1] = 1;
Matrix Ans = (A^T) * F;
printf("%d\n",Ans.s[(n - 1) * 9 + 1][1]);
return 0;
}
BZOJ1297 [SCOI2009]迷路 【矩陣優化dp】