問題 f: [shoi2013]超級跳馬
時間限制: 1 sec 記憶體限制: 256 mb
題目描述
現有乙個n行m列的棋盤,乙隻馬欲從棋盤的左上角跳到右下角。每一步它向右跳奇數列,且跳到本行或相鄰行。跳越期間,馬不能離開棋盤。例如,當n = 3, m = 10時,下圖是一種可行的跳法。
試求跳法種數mod 30011。
輸入 僅有一行,包含兩個正整數n, m,表示棋盤的規模。
輸出 僅有一行,包含乙個整數,即跳法種數mod 30011。
樣例輸入
3 5
樣例輸出
10 提示
對於100%的資料,1 ≤ n ≤ 50,2 ≤ m ≤ 10^9
看資料範圍就知道是矩陣乘。。。
轉移是要分奇數列和偶數列的,但實際上並沒有那麼麻煩。
對於這個方格
紅格的方案應該從所有的黃格轉移過來的,可以發現,藍格其實是其他黃格的字首和。所以紅格方案數=靠近自己的三個黃格方案數+兩排前對應那個格的方案數。
因此只要記錄兩列的方案數即可。轉移矩陣我寫成了這樣,
初始矩陣上面n行表示這一列的狀態,下面n行表示上一列的狀態。
但是還有乙個問題。在第三列時,會額外加一次第一行第一列的那個1。而那個1是被我們當作字首和加上去的。實際上並沒有那個字首和啊,我們並沒有跳一步到達1.因此相當於在第三列第一行多了乙個1.去掉的方法有很多,大部分都是再乘一邊什麼的,我yy出了一種方法:在第3列最上多了乙個1,跑到第m列產生的方案數,等於從第一列有乙個1,跑到第m-2列的方案數。而我們求m列第n行的方案實際上是f[m-1][n]+f[m-1][n-1]+f[m-2][n]的。那麼f[m-2][n]恰好就是多出來的方案數。不把他加上去就就成了。
#include
#include
#include
#include
#define mod 30011
#define ll long long
using
namespace
std;
int n,m,sz;
struct node
friend node operator *(node a,node b)
}ans,a,b;
int main()
for(int i=0;i1;
for(;m;m>>=1,b=b*b)if(m&1)ans=ans*b;
a=ans*a;
printf("%lld\n",(a.f[n-1][0]+a.f[n-2][0])%mod);
}
SHOI2013 超級跳馬
我是常年遊蕩於題解區的幽靈。直觀的想法就是字首和 差分優化dp,但還有些比較奇妙的方法or trick f i j f i 1 j 1 f i 1 j f i 1 j 1 color 因為可以一步跳到 f i j 的狀態也可以一步跳到 f i 2 j 反過來也成立 只考慮從左邊某個特定的列的轉移矩陣...
bzoj 4417 Shoi2013 超級跳馬
題意 現有乙個n行m列的棋盤,乙隻馬欲從棋盤的左上角跳到右下角。每一步它向右跳奇數列,且跳到本行或相鄰行。試求跳法種數mod 30011。題解 dp 矩陣乘法 快速冪 設f i j 表示走到第2i 1列,第 j 行的方案數,g i j 表示走到第2i 列,第j行的方案數。那麼f i j k 1i 1...
SHTSC2013 超級跳馬 矩陣快速冪
僅有一行,包含兩個正整數n,m,表示棋盤的規模。output 僅有一行,包含乙個整數,即跳法種數mod 30011。sample input 3 5sample output 10data constraint 對於10 的資料,1 n 10,2 m 10 對於50 的資料,1 n 10,2 m 1...