jzoj3294. 【SHTSC2013】超级跳马

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]}表示走到(i,j)(i,j)这个位置的方案数。
O(nm2)O(n*m^2)暴力转移。
50%
我们发现,上面的时间复杂度实在太大。
怎么办?我们发现转移的时候j都是奇偶列交替枚举的。
于是我们可以利用前缀和优化来分别记录奇数列与偶数列。
O(nm)O(n*m)
100%
我们发现,m极其的大。
那么很容易想到矩阵。
但是我们的转移是奇偶列交替来搞的。
这很难直接转移。
一个直观的想法——由于是交替来搞,我们直接把奇列与偶列连在一起,变成下图:
在这里插入图片描述
那么,我们发现,由于偶列是不变的,奇列是转移过去的。
那么我们的转移矩阵就很好推了。
首先,由于新的偶列与奇列都是继承原来的,所以说,右上与左下都是1矩阵(a[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.


原文地址:https://www.cnblogs.com/RainbowCrown/p/11148350.html