1. 程式人生 > 實用技巧 >洛谷P3990 [SHOI2013]超級跳馬

洛谷P3990 [SHOI2013]超級跳馬

題意

題目連結

分析

DP部分

這題乍一看是個水題...

可以很快看出\(DP\)的做法

\(dp[i][j]\)表示到了第\(i\)行第\(j\)列的方案數

那麼\(dp\)轉移方程很好寫了:

\[dp[i][j]=dp[i-1][j]+dp[i-1][j]+dp[i-1][j+1]+dp[i-2][j] \]

可能唯一的難點在於這個第四項吧...我這裡解釋一下這個方程的含義

我們當這個位置可能由前一列的上一個,前一列的這個,前一列的下一個一步到達(因為限制就是每次只能移動一行或者不動)

同時我們考慮一步到達這個位置的其它點,容易發現這些點都是可以一步到達\((i-2,j)\)的,所以我們把剩下的點的貢獻相當於全部都算在了\((i-2,j)\)

上面,而沒有剩下的點一定存在於前面三項加上的貢獻當中

然後這個題的\(O(nm)\)演算法就這樣做出來了

矩陣快速冪

但是我們看到資料範圍時才知這題並不簡單...暗藏殺機...

\(m\leq 10^9\) !!!

但是我們觀察一下上面的\(DP\)轉移方程,我們可以發現:對於每一列來說,當前這一項只會被前一項和前兩項統計到

所以我們可以考慮 狀壓 矩陣快速冪優化\(DP\)

我們矩陣要記錄的就是上一行和上兩行的狀態,共\(100*100\)

然後構造的狀態轉移矩陣就按照\(DP\)方程那樣把初始矩陣賦一下值就可以了,最後答案也不難得出,見程式碼即可

時間複雜度\(O(nlogm*(2n)^3)\),足以通過此題

程式碼

窩是看了這位巨佬的部落格才學會的,如有雷同只是看了就感覺寫的都一樣了QWQ

#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
	x=0;char ch=getchar();bool f=false;
	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	x=f?-x:x;
	return ;
}
template <typename T>
inline void write(T x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10^48);
	return ;
}
const int N=105,MOD=30011;
int n,m;
#define inc(a,b) (a+b>=MOD?a+b-MOD:a+b)
struct Matrix{
	int a[N][N];
	Matrix(){memset(a,0,sizeof(a));}
	Matrix operator *(Matrix B){
		Matrix C;
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				for(int k=1;k<=n;k++){
					C.a[i][j]=inc(C.a[i][j],a[i][k]*B.a[k][j]%MOD);
				}
			}
		}
		return C;
	}
};
Matrix QuickPow(Matrix A,int y){
	Matrix res;
	for(int i=1;i<=n;i++) res.a[i][i]=1;
	while(y){
		if(y&1) res=res*A;
		A=A*A;
		y>>=1;
	}
	return res;
}
Matrix base;
int ans1,ans2;
int main(){
	read(n),read(m);
	if(m<=2){
		if(n<=2&&m<=n) puts("1");
		else puts("0");
		return 0;
	}
	for(int i=1;i<=n;i++){
        base.a[i][i-1]=base.a[i][i]=base.a[i][i+n]=base.a[i+n][i]=1;
        if(i!=n)base.a[i][i+1]=1;
    }
    n<<=1;
    base=QuickPow(base,m-2);
    n>>=1;
    if(n==1){
    	write(base.a[1][1]);
    	return 0;
	}
	int n2=n<<1;
	ans1=(base.a[1][n2-1]+base.a[2][n2-1]+base.a[n+1][n2-1])%MOD,ans2=(base.a[1][n2]+base.a[2][n2]+base.a[n+1][n2])%MOD;
	write(inc(ans1,ans2)%MOD);
	return 0;
}