题解
题目意思有点不好懂,其实就是在数列中找到与 A_{i-1} 相邻的两项来限制 A_i 的值,问方案数。
首先凭感觉,感觉越往后面的数可能的情况是更少的,整体呈收束趋势。
我们设用来更新 A_i 的 L 和 R 为 L_i 和 R_i ,根据定义有 L_{i-1} \leq A_{i-1} \leq R_{i-1} ,现在考虑更新 A_i ,根据定义有 L_{i-1} \le L_i \leq A_{i-1} , R_{i-1} \ge R_i \ge A_{i-1} ,即L_{i-1} \leq L_{i}, R_{i-1} \geq R_{i} 。
这种收束的性质会为我们后面的dp转移提供便利。
考虑设计一个很朴素的状态,即 f_{i,k,l,r} 表示当前填到第 i 个数,A_1 到 A_{i-1} 中小于等于 k 的最大的数为 l ,大于等于 k 的最小的数为 r
转移时有以下几种情况:
- $k,l,r$ 不相等, $A_{i-1}$ 要么是 $l$ 要么是 $r$ ,
f_{i, k, l, r} = \sum_{j \leq l} f_{i-1, l, j, r}+\sum_{j \geq r} f_{i-1, r, l, j}
- $k=l=r$
若 A_{i-1}=k 那么f_{i,k, k, k} = \sum_{j \leq k} \sum_{z \geq k} f_{i-1,k, j, z}
否则,
f_{i,k,k,k}=\sum_{y\ne k}(\sum_{z\le y}f_{i-1,y,z,k}+\sum_{z\ge y}f_{i-1,y,k,z})
(y不等于k,不知道为什么latex乱掉了……)
这个 O(nr_i^4) 的做法肯定会T,可以用前缀和达到 O(nr_i^3) 计算发现过不了,但是实际上最大的点都能过,也许是我时间复杂度算错了吧。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int MOD=998244353; int n; int f[155][155][155]; int r[51],maxr; int sl[155][155][155],sr[155][155][155]; int main(){ cin>>n; for(int i=1;i<=n;i++)cin>>r[i],maxr=max(maxr,r[i]+1); for(int i=0;i<=maxr;i++){ sl[0][i][maxr]=sr[0][0][i]=1; } for(int i=1;i<=n;i++){ memset(f,0,sizeof(f)); for(int j=1;j<=r[i];j++){ for(int l=0;l<j;l++) for(int r=j+1;r<=maxr;r++) f[j][l][r]=(sl[l][l][r]+sr[r][l][r])%MOD; for(int r=j;r<=maxr;r++) f[j][j][j]=(f[j][j][j]+sl[j][maxr][r])%MOD; for(int k=0;k<=maxr;k++) if(k!=j)f[j][j][j]=(f[j][j][j]+sl[k][k][j]+sr[k][j][k])%MOD; } memset(sl,0,sizeof(sl)); for(int j=1;j<=r[i];j++) for(int l=0;l<=maxr;l++) for(int r=j;r<=maxr;r++) sl[j][l][r]=(f[j][l][r]+(l==0?0:sl[j][l-1][r]))%MOD; memset(sr,0,sizeof(sr)); for(int j=1;j<=r[i];j++) for(int l=0;l<=j;l++) for(int r=maxr;r>=0;r--) sr[j][l][r]=(f[j][l][r]+sr[j][l][r+1])%MOD; } int ans=0; for(int i=1;i<=r[n];i++) for(int l=0;l<=i;l++) for(int r=i;r<=maxr;r++) ans=(ans+f[i][l][r])%MOD; printf("%d",ans); return 0; } |