一个不太一样的做法
当(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))显然有(Lleq xleq R),我们下一个能填的数也只能在这个范围内。
当我们(A_i=y)的时候,考虑新的上下界分别是谁。
当(xleq yleq R)的时候,显然小于等于(y)中最大的是(x),大于等于(y)中最大的是(R),所以新的下界是(x),上界(R),三元组变成了((x,R,y))
当(Lleq 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)
当(pleq yleq k),(f_{i,j,k,p})向(f_{i+1,x,k,y})转移,这个转移和(j)这一维没有关系
当(jleq y< p),(f_{i,j,k,p})向(f_{i+1,j,x,y})转移,这个转移和(k)这一维没有关系
考虑一下是否可以去掉一维,上下界中只保存一个能否进行转移
显然是可以的,设(dp_{i,j,k})表示当前填了(i)个数,上/下界为(j),末尾填的数为(k)。我们强行规定当(kleq 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})负责(jleq y<p)的转移;(dp_{i,k,p})负责(pleq yleq 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
",ans);
}