[题面](https://www.luogu.org/problemnew/show/P4769)
吐槽:好像发的pdf题面的冒泡是挂挂的,还好我还会冒泡排序(逃
具体思路:首先发现当这个序列的最长下降序列长度大于2时,一定不符合要求
那么我们可以想出一个$O(n^2)$的DP
$f_i,j$表示前$i$个数,设其中最大的数为$mx$,后面的数中有$j$个数比$mx$小的方案数
然后发现$f_i,j$可以转移至$i+1,j+k$的位置($k>=-1$)
那么答案就是从$(0,0)$走到$(n,0)$的方案数,且路径不能低于x轴
那么可以把路径看成一个括号序列,x坐标+1,表示多一个右括号,y坐标表示左括号和右括号的差
那么我们枚举从哪个位置突破字典序的限制,然后后面就可以随机游走,求方案数就组合数搞搞,不能低于x轴就对称搞搞
AC代码
#include<bits/stdc++.h> using namespace std; #define int long long const int N=2e6+4; int n,i,j,m,a[N],ha=998244353; int fact[N],inv[N],factinv[N],vis[N]; int qpow(int a,int b) { int ans=1; while(b) { if(b%2)ans=ans*a%ha; a=a*a%ha;b=b/2; } return ans; } int T; int C(int x,int y) { if(x>y)return 0; return fact[y]*factinv[x]%ha*factinv[y-x]%ha; } int cal(int h,int dis) { if((dis-h)%2)return 0; int x=(dis-h)/2+h,y=(dis-h)/2; return C(y,dis); } int calc(int x,int y) { if(x<y) { return 0; } int dis=(x*2-y),h=y; return (ha+cal(y,2*x-y)-cal(y+2,2*x-y))%ha; } signed main() { fact[0]=1,factinv[0]=1; for(i=1;i<=2000000;i++) { if(i>1)inv[i]=(ha-(ha/i))*inv[ha%i]%ha;else inv[i]=1; fact[i]=fact[i-1]*i%ha; factinv[i]=factinv[i-1]*inv[i]%ha; } scanf("%lld",&T); while(T--) { scanf("%lld",&n); for(i=1;i<=n;i++)scanf("%lld",&a[i]); int mx=0,low=1,sum=0,ans=0;memset(vis,0,sizeof vis); for(i=1;i<n;i++) { if(a[i]>mx)sum+=a[i]-mx,mx=a[i];vis[a[i]]=1; for(;vis[low];low++); ans=(ans+calc(n-i+1,sum+1))%ha; if(mx>a[i]&&a[i]>low)break;sum--; } printf("%lld ",ans); } return 0; }