【题解】CF 2063F1 Counting Is Not Fun (Easy Version)
考虑初始的答案,显然为卡特兰数 \(H(n)\)。
考虑加入一对括号 \((l,r)\) 时对答案的贡献。(\((l,r)\) 表示有一对括号,左括号在 \(l\),右括号在 \(r\)。)
我们默认一开始有一对括号 \((0,n+1)\)。当出现一对括号 \((l,r)\) 时,首先要加上 \((l,r)\) 中的贡献,然后最小的包含了 \((l,r)\) 的括号要减去 \((l,r)\) 之间的贡献。具体地,可以用 \(hp_i\) 表示以 \(i\) 为右括号的括号中还有多少个空位,则这一对括号的贡献即为 \(H(hp_i)\)。预处理卡特兰数,时间复杂度为 \(O(n^2)\)。
#include<cstdio>
#include<iostream>
#include<stack>
#define ll long long
#define il inline
using namespace std;
namespace asbt{
namespace cplx{bool begin;}
const int maxn=5e3+5,mod=998244353;
il int qpow(int x,int y){
int res=1;
while(y){
if(y&1){
res=res*1ll*x%mod;
}
x=x*1ll*x%mod,y>>=1;
}
return res;
}
namespace cplx{
bool end;
il double usdmem(){return (&begin-&end)/1048576.0;}
}
int main(){
ios::sync_with_stdio(0),cin.tie(0);
int T,*fac=new int[maxn](),*inv=new int[maxn]();
fac[0]=fac[1]=1;
for(int i=2;i<=5e3;i++){
for(int j=1;j<=i;j++){
(fac[i]+=fac[j-1]*1ll*fac[i-j]%mod)%=mod;
}
}
// for(int i=0;i<=5e3;i++){
// cout<<fac[i]<<" ";
// }
// puts("");
for(int i=0;i<=5e3;i++){
inv[i]=qpow(fac[i],mod-2);
}
// for(int i=0;i<=5e3;i++){
// cout<<fac[i]*1ll*inv[i]%mod<<" ";
// }
// puts("");
cin>>T;
while(T--){
int n;
cin>>n;
int *hp=new int[n*2+5](),*f=new int[n*2+5]();
hp[n<<1|1]=n,f[n<<1|1]=-1;
int ans=fac[n];
cout<<ans<<" ";
for(int i=1,l,r,tot;i<=n;i++){
cin>>l>>r;
f[l]=1,f[r]=-1;
tot=r-l-1;
stack<int> zhan;
for(int j=l+1;j<r;j++){
if(f[j]==1){
zhan.push(j);
}
else if(f[j]==-1){
int tmp=zhan.top();
zhan.pop();
if(zhan.empty()){
tot-=j-tmp+1;
}
}
}
// cout<<tot<<"\n";
tot>>=1;
ans=ans*1ll*fac[tot]%mod;
hp[r]=tot;
for(int j=r+1;j<=(n<<1|1);j++){
if(f[j]==1){
zhan.push(j);
}
else if(f[j]==-1){
if(zhan.empty()){
ans=ans*1ll*inv[hp[j]]%mod;
hp[j]-=tot+1;
ans=ans*1ll*fac[hp[j]]%mod;
break;
}
else{
zhan.pop();
}
}
}
cout<<ans<<" ";
}
cout<<"\n";
delete[] hp,f;
}
delete[] fac,inv;
return 0;
}
}
int main(){return asbt::main();}

浙公网安备 33010602011771号