1. 程式人生 > >bzoj4417 [Shoi2013]超級跳馬

bzoj4417 [Shoi2013]超級跳馬

efi turn ref 題解 stdio.h sse const display pre

傳送門:http://www.lydsy.com/JudgeOnline/problem.php?id=4417

【題解】

令f[i,j]表示到第2i-1列第j行的方案數,g[i,j]表示到第2i行第j列的方案數。

那麽有

f[i,j]=Σg[1..i-1,j]+Σg[1..i-1,j-1]+Σg[1..i-1,j+1]

g[i,j]=Σf[1..i,j]+Σf[1..i,j-1]+Σf[1..i,j+1]

將f[i,j]和g[i,j]重新表示為前綴和形式

f[i,j]=f[i-1,j]+g[i-1,j]+g[i-1,j-1]+g[i-1,j+1]

g[i,j]=g[i-1,j]+f[i,j]+f[i,j-1]+f[i,j+1]

容易想到矩陣乘法

按照這種形式排列

f[i,1], f[i,2], ..., f[i,n], g[i,1], g[i,2], ..., g[i,n]

那麽g轉移要用到f怎麽辦?

我們想,讓這個矩陣連續乘2個轉移矩陣

第一個轉移完f和g的前綴和部分。到乘第二個矩陣的時候,f已經轉移完了,就能用f的信息了。

真正矩陣乘法把兩個轉移矩陣乘在一起做就行了。

要拓寬思路不要想著一個轉移矩陣搞定問題。

註意判斷m是奇偶的問題,以及n=1和不用做矩陣乘法等特判

技術分享
# include <stdio.h>
# include <assert.h>
# include <string
.h> # include <iostream> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 150 + 10; const int mod = 30011; # define RG register # define ST static struct matrix {
int a[M][M], n, m; inline void set(int _n, int _m) { n = _n, m = _m; memset(a, 0, sizeof a); } friend matrix operator *(matrix a, matrix b) { matrix c; c.set(a.n, b.m); assert(a.m == b.n); for (int i=1; i<=c.n; ++i) for (int j=1; j<=c.m; ++j) for (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; } friend matrix operator ^(matrix a, int b) { matrix c; c.set(a.n, a.m); assert(a.n == a.m); for (int i=1; i<=c.n; ++i) c.a[i][i] = 1; while(b) { if(b&1) c = c*a; a = a*a; b >>= 1; } return c; } inline void prt() { for (int i=1; i<=n; ++i, cout << endl) for (int j=1; j<=m; ++j) cout << a[i][j] << " "; } }A, T1, T2, T, B; int n, m; int main() { cin >> n >> m; T1.set(n+n, n+n), T2.set(n+n, n+n); for (int i=1; i<=n; ++i) { T1.a[i][i] = 1; T2.a[i][i] = 1; T1.a[i+n][i] = 1; T2.a[i][i+n] = 1; if(i != 1) { T1.a[i-1+n][i] = 1; T2.a[i-1][i+n] = 1; } if(i != n) { T1.a[i+1+n][i] = 1; T2.a[i+1][i+n] = 1; } T1.a[i+n][i+n] = 1; T2.a[i+n][i+n] = 1; } T = T1*T2; A.set(1, n+n); A.a[1][1] = 1; A.a[1][1+n] = 1; if(n != 1) A.a[1][1+n+1] =1; int times = (m-1)/2; if(times == 0) { if(m == 1) cout << A.a[1][n]; else cout << A.a[1][n+n]; return 0; } --times; A = A * (T^times); B = A * T; if(m&1) cout << ((B.a[1][n] - A.a[1][n]) % mod + mod) % mod; else cout << ((B.a[1][n+n] - A.a[1][n+n]) % mod + mod) % mod; return 0; }
View Code

bzoj4417 [Shoi2013]超級跳馬