QOJ 5047 Permutation
首先注意到一个事情,在 \(1\) 两端的数永远不可能跨过 \(1\)。根据这个东西,我们可以考虑分治。
我们设 \(work(l,r,L,R)\) 表示区间 \([l,r]\),左端有 \(L\) 个数可以随意重排,右边有 \(R\) 个数可以随意重排的方案数,考虑怎么进行计算。
不难注意到,若 \(L,R\) 包含的范围有交或者其中一个包含了整个区间,那这个区间可以随意重排。
不妨设 \(p\) 为 \([l,r]\) 中最小值的位置。考虑对 \(p\) 的位置进行分类讨论。
-
\(p\) 在左右两端包含的范围之间:那么直接删掉 \(p\),分治 \(p\) 的两边。
-
\(p\) 在左端包含的范围内:把这个数换到 \(l\) 的位置,然后删掉 \(l\) 这个位置继续分治。
-
\(p\) 在右端包含的范围内:把这个数换到 \(r\) 的位置,然后删掉 \(r\) 这个位置继续分治。
每种情况之后的 \(L,R\) 都是好处理的,可以自行思考。
AC code:
#include<bits/stdc++.h>
#define int long long
#define N 500005
#define pii pair<int,int>
#define x first
#define y second
#define mod 998244353
#define inf 2e18
using namespace std;
int T=1,n,m,a[N],p[N],f[N];
void init(){
f[0]=1;
for(int i=1;i<N;i++){
f[i]=f[i-1]*i%mod;
}
}
struct sgt{
int tr[N<<2];
void pushup(int u){
tr[u]=min(tr[u<<1],tr[u<<1|1]);
}
void build(int u,int l,int r){
if(l==r){
tr[u]=a[l];
return;
}
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
void modify(int u,int l,int r,int p,int v){
if(l==r){
tr[u]=v;
return;
}
int mid=l+r>>1;
if(p<=mid)modify(u<<1,l,mid,p,v);
else modify(u<<1|1,mid+1,r,p,v);
pushup(u);
}
int qry(int u,int l,int r,int L,int R){
if(l>=L&&r<=R)return tr[u];
int mid=l+r>>1;
int res=inf;
if(L<=mid)res=min(res,qry(u<<1,l,mid,L,R));
if(R>mid)res=min(res,qry(u<<1|1,mid+1,r,L,R));
return res;
}
}s;
int work(int l,int r,int L,int R){
if(L+R>r-l+1||max(L,R)>=r-l+1){
return f[r-l+1];
}
int mn=s.qry(1,1,n,l,r);
int pos=p[mn];
if(pos>l+L-1&&pos<r-R+1){
return work(l,pos-1,L,(pos-l>=m)*m)*work(pos+1,r,(r-pos>=m)*m,R)%mod;
}
else if(pos<=l+L-1){
swap(p[a[l]],p[a[pos]]);
swap(a[l],a[pos]);
s.modify(1,1,n,l,a[l]);
s.modify(1,1,n,pos,a[pos]);
return L*work(l+1,r,min(L+m-1,r-l),R)%mod;
}
else{
swap(p[a[r]],p[a[pos]]);
swap(a[r],a[pos]);
s.modify(1,1,n,r,a[r]);
s.modify(1,1,n,pos,a[pos]);
return R*work(l,r-1,L,min(R+m-1,r-l))%mod;
}
}
void solve(int cs){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
p[a[i]]=i;
}
s.build(1,1,n);
cout<<work(1,n,0,0)<<'\n';
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>T;
init();
for(int cs=1;cs<=T;cs++){
solve(cs);
}
return 0;
}

浙公网安备 33010602011771号