【[SCOI2009]迷路】
阿新 • • 發佈:2019-01-01
大水題一遍
過掉比較繁瑣的拆點還是非常開心的
發現每一條邊的邊權可能不是\(1\),但是邊權的範圍非常小,同時點數也非常小,只有\(n<=10\),所以我們可以將一個點拆成九個點,之後隨便一連邊就跑過去了
程式碼
#include<iostream> #include<cstdio> #include<cstring> #define re register #define maxn 105 #define LL long long const int mod=2009; int a[maxn][maxn],ans[maxn][maxn]; int sz; inline void did_a() { int mid[maxn][maxn]; for(re int i=1;i<=sz;i++) for(re int j=1;j<=sz;j++) mid[i][j]=a[i][j],a[i][j]=0; for(re int k=1;k<=sz;k++) for(re int i=1;i<=sz;i++) for(re int j=1;j<=sz;j++) a[i][j]=(a[i][j]+mid[i][k]*mid[k][j])%mod; } inline void did_ans() { int mid[maxn][maxn]; for(re int i=1;i<=sz;i++) for(re int j=1;j<=sz;j++) mid[i][j]=ans[i][j],ans[i][j]=0; for(re int k=1;k<=sz;k++) for(re int i=1;i<=sz;i++) for(re int j=1;j<=sz;j++) ans[i][j]=(ans[i][j]+mid[i][k]*a[k][j])%mod; } inline void quick(LL b) { while(b) { if(b&1ll) did_ans(); b>>=1ll; did_a(); } } inline int read() { char c=getchar(); int x=0; while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar(); return x; } int n; LL m; char S[maxn]; int main() { n=read(),m=read(); sz=n*10; for(re int i=1;i<=n;i++) { int now=(i-1)*10; for(re int j=2;j<=9;j++) a[j+now-1][j+now]=1; } for(re int i=1;i<=n;i++) { scanf("%s",S+1); int now=(i-1)*10; for(re int j=1;j<=n;j++) { if(S[j]=='0') continue; int to=S[j]-48; a[now+9][(j-1)*10+10-to]=1; } } for(re int i=1;i<=sz;i++) ans[i][i]=1; quick(m); printf("%d\n",ans[9][(n-1)*10+9]); return 0; }