结论:一个序列是好序列当且仅当其不存在长度为3的下降子序列
证明:考虑提示,一个长度为3的下降子序列必然会交换三次,
而这三次带来的收益实际上只有2,因此不合法
同时还可以得到:第i个数,要么是前缀最大值,要么是之前的mex
(即要么让他之前没有比他大的,要么让他之后没有比他小的)
用f[i][j]表示剩余i个数,当前最大值为n-j的填写方案(先不考虑字典序)
根据上述结论,得到递推式:$f[i][j]=\sum_{k=0}^{j}f[i-1][k]$,其中f[0][0]=1
即$f[i][j]=f[i-1][j]+f[i][j-1]$,解得$f[i][j]=c(i+j,j)-c(i+j,j-2)$(构造的方法:发现任意个c(i+j+k1,j+k2)都符合,再把常数配出来即可)
先预处理阶乘及逆元,然后就可以快速计算f了,之后枚举i,并求出:1.i之前与p相同;2.i位置上比p大的好序列个数
设i之前的最大值是x,mex是y,分别考虑填新最大值和k的贡献,有$ans+=f[n-i][n-x]\cdot [p[i]<y\le x]+f[n-i+1][n-\max(x,p[i])-1]$,累计即可
View Code
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define mod 998244353 4 #define N 1200005 5 int t,n,k,x,y,ans,vis[N],fac[N],inv[N]; 6 int c(int n,int m){ 7 if (m<0)return 0; 8 return 1LL*fac[n]*inv[m]%mod*inv[n-m]%mod; 9 } 10 int f(int n,int m){ 11 return (c(n+m,m)-c(n+m,m-1)+mod)%mod; 12 } 13 int main(){ 14 fac[0]=inv[0]=inv[1]=1; 15 for(int i=1;i<N-4;i++)fac[i]=1LL*fac[i-1]*i%mod; 16 for(int i=2;i<N-4;i++)inv[i]=1LL*(mod-mod/i)*inv[mod%i]%mod; 17 for(int i=2;i<N-4;i++)inv[i]=1LL*inv[i-1]*inv[i]%mod; 18 scanf("%d",&t); 19 while (t--){ 20 scanf("%d",&n); 21 x=ans=0; 22 y=1; 23 for(int i=1;i<=n+1;i++)vis[i]=0; 24 for(int i=1;i<=n;i++){ 25 scanf("%d",&k); 26 if ((k<y)&&(y<=x))ans=(ans+f(n-i,n-x))%mod; 27 x=max(x,k); 28 if (x<n)ans=(ans+f(n-i+1,n-x-1))%mod; 29 if ((k!=x)&&(k!=y)){ 30 for(i++;i<=n;i++)scanf("%*d"); 31 break; 32 } 33 vis[k]=1; 34 while (vis[y])y++; 35 } 36 printf("%d\n",ans); 37 } 38 }