洛谷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;
}
posted @ 2020-12-06 18:36  __Anchor  阅读(55)  评论(0编辑  收藏  举报