分析:
我们先考虑为什么有些排列是好的,有些排列不好
可以发现交换次数的下界这个式子即表示每个位置的数到它原本该在的位置,且有个
1
/
2
1/2
1/2表示每次交换必须要让被交换的两个数都离自己的目标位置更近一步
所以我们如果把每个数到他的目的地看做一个箭头,则任意两个同向箭头不能有完全包含的关系
因为如果出现了包含的箭头,那大箭头一定会把小箭头往反向移动一步
所以我们在一个位置填的数只能是当前未使用的数的最小值或者比之前填过的所有数都大
则
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示当前到第i个数,当前填的数在剩余的数中为第j大
那么可以写出转移
f
[
i
]
[
j
]
=
∑
k
=
0
i
f
[
i
−
1
]
[
j
−
k
]
f[i][j]=\sum_{k=0}^if[i-1][j-k]
f[i][j]=∑k=0if[i−1][j−k]
前缀和优化
f
[
i
]
[
j
]
=
f
[
i
]
[
j
−
1
]
+
f
[
i
−
1
]
[
j
]
f[i][j]=f[i][j-1]+f[i-1][j]
f[i][j]=f[i][j−1]+f[i−1][j]
字典序应该不难解决吧
这就有80pts了
打表发现这是卡特兰数(我不会证 )
然后100pts就膜题解去了
Code(100pts):
#include<bits/stdc++.h>
#define mod 998244353
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
inline int dec(int x,int y){x-=y;if(x<0) x+=mod;return x;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline int ksm(int a,int b){int res=1;for(;b;b>>=1,a=mul(a,a)) if(b&1) res=mul(res,a);return res;}
inline void inc(int &x,int y){x+=y;if(x>=mod) x-=mod;}
const int N=2e6;
int a[N],b[N],c[N],n;
int fac[N],ifac[N];
namespace bit{
int tr[N];
inline int lb(int x){return x&-x;}
inline void add(int x){for(int i=x;i<=n;i+=lb(i)) ++tr[i];}
inline int ask(int x){int res=0;for(int i=x;i;i-=lb(i)) res+=tr[i];return res;}
}
using namespace bit;
inline void init(int n){
fac[0]=ifac[0]=1;
for(int i=1;i<=n;i++) fac[i]=mul(fac[i-1],i);
ifac[n]=ksm(fac[n],mod-2);
for(int i=n-1;i;i--) ifac[i]=mul(ifac[i+1],i+1);
}
inline int C(int n,int m){if(n<m) return 0;return mul(fac[n],mul(ifac[m],ifac[n-m]));}
inline int calc(int n,int m){
if(!m) return 1;
if(m==1) return n;
return dec(C(n+m-1,m),C(n+m-1,m-2));
}
int main(){
init(1500000);
int t=read();
while(t--){
memset(tr,0,sizeof(tr));
n=read();
for(int i=1;i<=n;i++){
a[i]=read();add(a[i]);
c[i]=ask(a[i]-1);
b[i]=n-a[i]-(i-1-c[i]);
}
int ans=0,cnt=n;
for(int i=1;i<=n;i++){
bool flag=(b[i]<cnt);
if(flag) cnt=b[i];
if(!cnt) break;
inc(ans,calc(n-i+1,cnt-1));
if(!flag && c[i]!=a[i]-1) break;
}
cout<<ans<<"\n";
}
return 0;
}