Luogu P3990 [SHOI2013]超級跳馬
阿新 • • 發佈:2018-05-29
討論 std while code 有關 矩陣快速冪 都是 cstring 我們
這道題還是一道比較不可做的矩陣題
首先我們先YY一個遞推的算法:令f[i][j]表示走到第i行第j列時的方案數,那麽有以下轉移:
f[i][j]=f[i-1][j-2*k+1]+f[i+1][j-2*k+1]+f[i][j-2*k+1](1<=k<=i/2)
但這樣是很慢的,然後我們就可以前綴和優化
這裏有兩種方法,一個是用奇偶數行進行討論,還有一種我認為是比較清晰的也比較容易理解
我們先來看一張圖:
我們令f[i][j]表示前面可以轉移到它的前綴和。例如圖中的藍色格子就是前6個格子的和
然後我們發現紅色格子就是由藍色格子+與它相近(i坐標差值為1)的3個黃色格子的值
然後就可以O(nm)求,但是這顯然是過不了的
但是我們仔細研究一下發現每一次的轉移都是等價的,所以我們用矩陣優化
由於每一列的值都和它前面兩列有關,所以我們需要一個2*n*2*n的矩陣來轉移,這個的話大概長這樣(n=3時)
具體還是看CODE吧,然後就是常規的矩陣快速冪了
CODE
#include<cstdio> #include<cstring> using namespace std; typedef long long LL; const int N=55,mod=30011; int n,m; struct Matrix { int n,m; LL a[N<<1][N<<1]; inline void Dt_init(void) { register int i; memset(a,0,sizeof(a)); n>>=1; for (i=1;i<=n;++i) a[i][i+n]=a[i+n][i]=1; for (i=1;i<=n;++i) { if (i^1) a[i][i-1]=1; if (i^n) a[i][i+1]=1; a[i][i]=1; } n<<=1; } inline void cri_init(void) { register int i; memset(a,0,sizeof(a)); for (i=1;i<=n;++i) a[i][i]=1; } }; inline Matrix mul(Matrix A,Matrix B) { Matrix C; C.n=A.n; C.m=B.m; memset(C.a,0,sizeof(C.a)); for (register int i=1;i<=C.n;++i) for (register int j=1;j<=C.m;++j) for (register int k=1;k<=A.m;++k) C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%mod; return C; } inline Matrix quick_pow(Matrix A,int p) { Matrix T; T.n=T.m=A.n; T.cri_init(); while (p) { if (p&1) T=mul(T,A); A=mul(A,A); p>>=1; } return T; } int main() { scanf("%d%d",&n,&m); Matrix A; A.n=A.m=n<<1; A.Dt_init(); A=quick_pow(A,m-2); printf("%lld",(A.a[n][1]+A.a[n-1][1])%mod); return 0;
Luogu P3990 [SHOI2013]超級跳馬