Description
Input
仅有一行,包含两个正整数n, m,表示棋盘的规模。
Output
仅有一行,包含一个整数,即跳法种数mod 30011。
Sample Input
3 5
Sample Output
10
Data Constraint
对于10%的数据,1 ≤ n ≤ 10,2 ≤ m ≤ 10;
对于50%的数据,1 ≤ n ≤ 10,2 ≤ m ≤ 10^5;
对于80%的数据,1 ≤ n ≤ 10,2 ≤ m ≤ 10^9;
对于100%的数据,1 ≤ n ≤ 50,2 ≤ m ≤ 10^9。
题解
比赛时心态崩了没有调出来,血亏。我还是太蔡了。
10%
我们考虑DP。设f[i,j]f_{[i,j]}f[i,j]表示走到(i,j)(i,j)(i,j)这个位置的方案数。
O(n∗m2)O(n*m^2)O(n∗m2)暴力转移。
50%
我们发现,上面的时间复杂度实在太大。
怎么办?我们发现转移的时候j都是奇偶列交替枚举的。
于是我们可以利用前缀和优化来分别记录奇数列与偶数列。
O(n∗m)O(n*m)O(n∗m)
100%
我们发现,m极其的大。
那么很容易想到矩阵。
但是我们的转移是奇偶列交替来搞的。
这很难直接转移。
一个直观的想法——由于是交替来搞,我们直接把奇列与偶列连在一起,变成下图:
那么,我们发现,由于偶列是不变的,奇列是转移过去的。
那么我们的转移矩阵就很好推了。
首先,由于新的偶列与奇列都是继承原来的,所以说,右上与左下都是1矩阵(a[i,i]=1a[i,i]=1a[i,i]=1)
然后,由于转移的新奇列是要与偶列进行DP的,所以左上是一个dp矩阵(很好推)
但是新的奇列与原来的奇列是不dp的,所以右下是什么都没有的。
直接快速幂即可。
标程
type
arr=array[1..100,1..100] of int64;
var
i,j,k,l,n,m,r,p,ans1,ans2:longint;
mo:int64=30011;
a,b,jl:arr;
function qsm(a,b:int64):int64;
var
t,y:int64;
begin
t:=1;
y:=a;
while b>0 do
begin
if b mod 2=1 then t:=t*y mod mo;
y:=y*y mod mo;
b:=b div 2;
end;
exit(t);
end;
function cheng(a,b:arr;p:longint):arr;
var
i,j,k:longint;
begin
fillchar(cheng,sizeof(cheng),0);
for i:=1 to p do
begin
for j:=1 to p do
begin
for k:=1 to p do
begin
cheng[i,j]:=(cheng[i,j]+a[i,k]*b[k,j]) mod mo;
end;
end;
end;
exit(cheng);
end;
function ksm(a:arr;b:int64):arr;
var
t,y:arr;
begin
t:=a;
y:=a;
dec(b);
while b<>0 do
begin
if(b and 1)=1 then
t:=cheng(t,y,p);
y:=cheng(y,y,p);
b:=b shr 1;
end;
exit(t);
end;
begin
//assign(input,'0data.in');reset(input);
//assign(output,'0data.out');rewrite(output);
readln(n,m);
p:=2*n;
for i:=1 to n do
begin
a[i,i]:=1;
if i>1 then
begin
a[i-1,i]:=1;
a[i,i-1]:=1;
end;
end;
for i:=1 to n do
begin
a[i+n,i]:=1;
a[i,n+i]:=1;
end;
m:=m-1;
jl:=a;
b:=ksm(jl,m);
fillchar(a,sizeof(a),0);
a[1,1]:=1;
b:=cheng(a,b,p);
if n=1 then
begin
writeln(b[1,n*2]);
halt;
end;
writeln((b[1,n*2]+b[1,n*2-1]) mod mo);
end.
end.