[JXOI2017]数列

题目

一个不太一样的做法

\(A_{i-1}=x\),称\(A_1\)\(A_{i-2}\)中大于等于\(A_{i-1}\)的最小值\(R\)为上界,\(A_1\)\(A_{i-2}\)中小于等于\(A_{i-1}\)的最大值\(L\)为下界。对于一组\((L,R,x)\)显然有\(L\leq x\leq R\),我们下一个能填的数也只能在这个范围内。

当我们\(A_i=y\)的时候,考虑新的上下界分别是谁。

\(x\leq y\leq R\)的时候,显然小于等于\(y\)中最大的是\(x\),大于等于\(y\)中最大的是\(R\),所以新的下界是\(x\),上界\(R\),三元组变成了\((x,R,y)\)

\(L\leq y< x\)的时候,新的上界是\(x\),下界是\(L\),三元组变成了\((L,x,y)\)

到这里我们就可以写一个dp了,设\(f_{i,j,k,p}\)表示填了\(i\)个数,末尾三元组的状态是\((j,k,p)\),转移的时候枚举下一位填什么推出下一个三元组即可。状态数是\(O(nr_i^3)\),转移是\(O(r_i)\)的,复杂度是\(O(nr_i^4)\)不是很能接受

再观察一下这个dp的转移,发现它非常别致,我们枚举下一位填的数\(y\)

\(p\leq y\leq k\)\(f_{i,j,k,p}\)\(f_{i+1,x,k,y}\)转移,这个转移和\(j\)这一维没有关系

\(j\leq y< p\)\(f_{i,j,k,p}\)\(f_{i+1,j,x,y}\)转移,这个转移和\(k\)这一维没有关系

考虑一下是否可以去掉一维,上下界中只保存一个能否进行转移

显然是可以的,设\(dp_{i,j,k}\)表示当前填了\(i\)个数,上/下界为\(j\),末尾填的数为\(k\)。我们强行规定当\(k\leq j\)的时候,\(j\)为上界;当\(k>j\)的时候,\(j\)为下界
即对于原来的\(f_{i,j,k,p}\)拆分成了两个状态\(dp_{i,j,p}\)\(dp_{i,k,p}\),这两个状态各自完成\(f_{i,j,k,p}\)的一部分转移。其中\(dp_{i,j,p}\)负责\(j\leq y<p\)的转移;\(dp_{i,k,p}\)负责\(p\leq y\leq k\)的转移。注意转移之后得到的仍旧是一个完整的上下界都有的状态,我们还是要把这个状态拆分一下

转移的时候还是枚举下一位填什么数,根据填的数推出转移的状态即可。注意当一下位填的数和上下界相等时,新的上下界就固定了。

这样的状态数就变成了\(O(nr_i^2)\),复杂度是\(O(nr_i^3)\),不知道为什么跑的比较快,luogu最优解,loj位列rk3

代码

#include<bits/stdc++.h>
#define re register
#define max(a,b) ((a)>(b)?(a):(b))
inline int read() {
	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const int maxn=155;
const int mod=998244353;
inline int qm(int x) {return x>=mod?x-mod:x;}
int h[55],n,o,R,dp[2][maxn][maxn];
int main() {
	n=read();for(re int i=1;i<=n;i++) h[i]=read(),R=max(R,h[i]);R++;
	for(re int i=1;i<=h[2];++i) 
		for(re int j=1;j<=h[1];++j) {
			if(j>=i) {if(i!=j) dp[0][i][0]++;}
			else dp[0][i][R]++;
			dp[0][i][j]++;
		}
	for(re int i=3;i<=n;i++,o^=1) {
		memset(dp[o^1],0,sizeof(dp[o^1]));
		for(re int j=1;j<=h[i-1];j++)
			for(re int k=0;k<=R;++k) {
				if(!dp[o][j][k]) continue;
				if(k<j) {
					for(re int p=k;p<j;p++)
					if(p<=h[i]&&p>0) {
						if(p==k) {
							dp[o^1][p][p]=qm(dp[o^1][p][p]+dp[o][j][k]);
							continue;
						}
						dp[o^1][p][k]=qm(dp[o^1][p][k]+dp[o][j][k]);
						dp[o^1][p][j]=qm(dp[o^1][p][j]+dp[o][j][k]);
					}
				}
				else {
					for(re int p=j;p<=k;++p)
					if(p<=h[i]&&p>0) {
						if(p==j||p==k) {
							dp[o^1][p][p]=qm(dp[o^1][p][p]+dp[o][j][k]);
							continue;
						}
						dp[o^1][p][j]=qm(dp[o^1][p][j]+dp[o][j][k]);
						dp[o^1][p][k]=qm(dp[o^1][p][k]+dp[o][j][k]);
					}
				}
			}
	}
	int ans=0;
	for(re int i=1;i<=h[n];++i)
		for(re int j=i;j<=R;++j) ans=qm(ans+dp[o][i][j]);
	return !printf("%d\n",ans);
}
posted @ 2019-10-12 07:59  asuldb  阅读(251)  评论(0编辑  收藏  举报