大致计算是 O(nlogn)。跑不满,但是跑得好慢。赛时卡了一下常才过。是不是常数比较大。
大致思路就是先离散化后找出全部不能移动的点,然后找出放在每两个点之间的全部点,然后用DP计算出能够组成的全部序列然后乘起来。
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const LL N=1e5+100,p=998244353;
LL n,a[N],tr[N],b[N],cnt,c[N],sum,ans=1,mp[N] ;
void add (LL x,LL w) {
for (LL i=x;i<=N;i+=(i&(-i))) {
(tr[i]+=w) %=p ;
}
}
LL cx (LL x) {
LL ans=0 ;
for (LL i=x;i>=1;i-=(i&(-i))) {
(ans+=tr[i]) %=p ;
}
return ans ;
}
inline void sol (LL l,LL r) {
memset (tr,0,sizeof tr) ;
for (LL j=l;j<=r;j++) {
// cout<<c[j]<<"\n" ;
LL tp=cx (c[j])-cx (c[j]-1) ;
add (c[j],cx (c[j])) ;
if (!tp) add (c[j],1);
else add (c[j],1-tp) ;
// for (LL i=1;i<=100;i++) cout<<tr[i];
}
// cout<<"\n" ;
}
int main () {
cin>>n;
for (LL i=1;i<=n;i++) {
cin>>a[i] ;
b[++cnt]=a[i] ;
}
sort (b+1,b+cnt+1) ;
LL len=unique (b+1,b+cnt+1)-b-1 ;
// for (LL i=1;i<=cnt;i++) {
// cout<<b[i]<<" " ;
// }
for (LL i=1;i<=n;i++) {
a[i]=lower_bound (b+1,b+len+1,a[i])-b ;
}
cnt=0 ;
for (LL i=1;i<=n;i++) {
if (!cx (a[i]-1)) {
b[++cnt]=a[i] ;
}
else {
c[++sum]=a[i] ;
}
add (a[i],1) ;
}
sort (b+1,b+cnt+1) ;
sort (c+1,c+sum+1) ;
// for (LL i=1;i<=cnt;i++) {
// cout<<b[i]<<" " ;
// }
// cout<<"\n" ;
// for (LL i=1;i<=sum;i++) {
// cout<<c[i]<<" ";
// }
// cout<<"\n\n" ;
LL l=1,r=1,s=0 ;
b[++cnt]=1e18 ;
for (LL i=1;i<=cnt;i++) {
s=0 ;
if (c[r]>b[i]) continue ;
while (c[r]<=b[i]&&r<=sum) r++,s++ ;
r-- ;
sol (l,r) ;
// cout<<cx (c[r])<<"\n" ;
(ans*=cx (c[r])+1 )%=p ;
// cout<<"id:"<<i<<":"<<s<<" ";
// cout<<l<<" "<<r<<"\n" ;
r++ ;
l=r ;
}
cout<<ans ;
// else cout<<1 ;
return 0;
}