题解:CF1976E Splittable Permutations
题意
对于一个数组,每次遵守以下规则将其分成两个数组:
- 大小至少为
2 。 - 从某个位置分开,左边的最大值记作
l_i ,右边最大值记作r_i 。
给定你操作次数
Sol
模拟切割操作,发现可以确定出现元素的相对顺序,具体来说就是
接下来考虑插入未确定的元素,由于每次切割有最大值的限制,插入
由于随着
不妨设
对于在链表中的
对于不在链表中的
答案就是:
时间复杂度
感觉描述的好抽象。
Code
#include<bits/stdc++.h>
#define ll long long
#define N 300005
#define endl "\n"
#define fi first
#define se second
using namespace std;
const ll mod=998244353;
const ll inf=1e18;
const double eps=1e-6;
ll n,m,l[N],r[N];
ll a[N],x[N],y[N],cnt[N];
vector<ll>v;
void sol(){
cin>>n>>m;
for(int i=1;i<=m;i++)cin>>x[i];
for(int i=1;i<=m;i++)cin>>y[i];
l[x[1]]=0;
r[0]=x[1];
a[x[1]]=x[1];
for(int i=1;i<=m;i++){
if(a[x[i]]){
a[y[i]]=y[i];
r[y[i]]=r[x[i]];
l[y[i]]=x[i];
l[r[x[i]]]=y[i];
r[x[i]]=y[i];
}else{
a[x[i]]=x[i];
r[x[i]]=y[i];
l[x[i]]=l[y[i]];
r[l[y[i]]]=x[i];
l[y[i]]=x[i];
}
}
for(int j=r[0];j;j=r[j])v.push_back(j);
cnt[v[0]]=1,cnt[v.back()]=1;
for(int i=1;i<v.size();i++)cnt[max(v[i],v[i-1])]++;
ll res=1,ans=0;
for(int i=n;i>=1;i--){
if(!a[i]){
res=res*ans%mod;
ans=(ans+1)%mod;
}
ans=(ans+cnt[i])%mod;
}
cout<<res<<endl;
}
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
ll ttt=1;
while(ttt--)sol();
return 0;
}