题意
给出 nnn 与长度为 n−1n-1n−1 的序列 vvv,下标从 111 开始。求满足下面条件的长度为 nnn 的排列 ppp 的个数对 998244353998244353998244353 取模后的结果:
∀1≤i<n,vi=min(max1≤j≤ipj,maxi+1≤j≤npj) \forall 1 \le i<n,v_i=\min(\max_{1 \le j \le i} p_j,\max_{i+1 \le j \le n} p_j) ∀1≤i<n,vi=min(1≤j≤imaxpj,i+1≤j≤nmaxpj)
思路
首先,我们考虑 nnn 在排列中的位置 xxx,合法的 vvv 的性质。那么,
vi={max1≤j≤ipj,i<xmaxi+1≤j≤npj,i≥x v_i= \begin{cases} \max_{1 \le j \le i} p_j,i<x \\ \max_{i+1 \le j \le n} p_j,i \ge x \end{cases} vi={max1≤j≤ipj,i<xmaxi+1≤j≤npj,i≥x
而 max1≤j≤ipj\max_{1 \le j \le i} p_jmax1≤j≤ipj 是非递减的,maxi+1≤j≤npj\max_{i+1 \le j \le n} p_jmaxi+1≤j≤npj 是非递增的,所以 vvv 一定是先非降后非增的,否则答案为 000。
我们还容易发现,如果 i<x,vi=vali<x,v_i=vali<x,vi=val,那么 valvalval 必然会在 111 到 iii 中出现。而排列中 valvalval 只会出现一次,且 j<xj<xj<x,故不可能存在 j≥xj \ge xj≥x 满足 vj=valv_j=valvj=val。同理,如果 i≥x,vi=vali \ge x,v_i=vali≥x,vi=val,则不可能存在 j<xj<xj<x 满足 vj=valv_j=valvj=val。
另外,若 n−1n-1n−1 在排列中的位置在 nnn 的左边,那么有 vx−1=max1≤i≤x−1pi=n−1v_{x-1}=\max_{1 \le i \le x-1} p_i=n-1vx−1=max1≤i≤x−1pi=n−1;否则 vx=maxx+1≤i≤npi=n−1v_x=\max_{x+1 \le i \le n} p_i=n-1vx=maxx+1≤i≤npi=n−1,即 n−1n-1n−1 一定出现在 vvv 中。同时,排列两部分不可能都含有 nnn,所以 nnn 不可能在 vvv 中。
综合以上诸性质,可得对于序列 vvv,存在合法排列的必要条件:
- vvv 中含有 n−1n-1n−1
- vvv 中不含 nnn
- vvv 先非降后非增
且若 nnn 在排列中的位置为 xxx,那么需满足 vx−1v_{x-1}vx−1 与 vxv_xvx 有且仅有一个 n−1n-1n−1。(若有零个,那么违背了先升后降规则;若有两个,那么违背了左右不重复规则)
接下来考虑答案个数。
容易发现,对于一个 vvv,能满足 vx−1v_{x-1}vx−1 与 vxv_xvx 有且仅有一个 n−1n-1n−1 的 xxx 有两个,因为其先增后降,且最大值为 n−1n-1n−1。而这两种的答案个数是相等的(证明如下),所以我们只需求出 px=n,vx−1<n−1,vx=n−1p_x=n,v_{x-1}<n-1,v_x=n-1px=n,vx−1<n−1,vx=n−1 的答案个数再乘 222 即可。
::::info关于上述两个情况答案相等的证明
令一个合法答案排列 p1,p2,...,px1−1,n,px1,...,pn−1p_1,p_2,\dots,p_{x_1-1},n,p_{x_1},\dots,p_{n-1}p1,p2,...,px1−1,n,px1,...,pn−1 的对应排列为 p1,p2,...,px2−1,n,px2,...,pn−1p_1,p_2,\dots,p_{x_2-1},n,p_{x_2},\dots,p_{n-1}p1,p2,...,px2−1,n,px2,...,pn−1,那么 ∀x1≤i<x2,vi=n−1\forall x_1 \le i<x_2,v_i=n-1∀x1≤i<x2,vi=n−1。
分类讨论:1≤i<x11 \le i<x_11≤i<x1 或 x2≤i<nx_2 \le i<nx2≤i<n,显然两个排列的 viv_ivi 都为 max1≤j≤ipj\max_{1 \le j \le i} p_jmax1≤j≤ipj;x1≤i<x2x_1 \le i<x_2x1≤i<x2,分成两部分后 nnn 与 n−1n-1n−1 一定不会被分到相同的区间里,所以两区间最大值的最小值即为 n−1n-1n−1。所以,若一排列满足 vvv 的限制,那么其对应排列也同样满足。反之同理。故两者互为充要条件。证毕。
::::
对于 1≤i<x1 \le i<x1≤i<x,若 vi−1<viv_{i-1}<v_ivi−1<vi,则说明区间 111 到 i−1i-1i−1 不含 viv_ivi 但区间 111 到 iii 包含之,所以 pip_ipi 必然等于 viv_ivi,情况数为 111。若 vi−1=viv_{i-1}=v_ivi−1=vi,那么 pip_ipi 一定在 111 到 viv_ivi 之间,且不能取已取过的数。x≤i≤nx \le i \le nx≤i≤n 同理。而左右两端中,可选择的限制相同,且可选择的值域区间不断变大(越接近 xxx,vvv 越大),所以用双指针维护现在取到的左端点与右端点,并不断向 xxx 逼近,分别终止于 x−1x-1x−1 与 xxx。最开始时答案为 111。每次逼近,以左段区间为例,若 vi−1<viv_{i-1}<v_ivi−1<vi,则答案不变;否则该数可取值的个数即为 viv_ivi 减去已遍历过的数的个数,并用答案乘之。然后将已取过的个数加一。
即有转移:
cpp
while(nowl<nr||nowr>=nr){
if(nowl<nr&&a[nowl]<a[nowr]||nowr==nr-1){
if(nowl>1&&a[nowl]==now){
if(now<=cnt){
ans=0;
break;
}
ans=ans*(now-cnt)%mod;
}
now=max(now,a[nowl]),nowl++;
}else{
if(nowr<n-1&&a[nowr]==now){
if(now<=cnt){
ans=0;
break;
}
ans=ans*(now-cnt)%mod;
}
now=max(now,a[nowr]),nowr--;
}
cnt++;
}
最后记得乘 222。
完整代码
cpp
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e6+5,mod=998244353;
int n;
int a[maxn],b[maxn];
void solve(){
cin>>n;
for(int i=1;i<=n;i++){
b[i]=0;
}
for(int i=1;i<n;i++){
cin>>a[i];
}
int nl=1,nr=n-1;
while(nl<n-1&&a[nl]<=a[nl+1]){
b[a[nl]]|=1;
nl++;
}
while(nr>1&&a[nr-1]>=a[nr]){
b[a[nr]]|=2;
nr--;
}
b[a[nl]]|=1,b[a[nr]]|=2;
if(nl<nr){
cout<<"0\n";
return;
}
if(b[n]||!b[n-1]){
cout<<"0\n";
return;
}
for(int i=1;i<n-1;i++){
if(b[i]>2){
cout<<"0\n";
return;
}
}
int ans=1;
int nowl=1,nowr=n-1,cnt=0,now=0;
while(nowl<nr||nowr>=nr){
if(nowl<nr&&a[nowl]<a[nowr]||nowr==nr-1){
if(nowl>1&&a[nowl]==now){
if(now<=cnt){
ans=0;
break;
}
ans=ans*(now-cnt)%mod;
}
now=max(now,a[nowl]),nowl++;
}else{
if(nowr<n-1&&a[nowr]==now){
if(now<=cnt){
ans=0;
break;
}
ans=ans*(now-cnt)%mod;
}
now=max(now,a[nowr]),nowr--;
}
cnt++;
}
cout<<ans*2%mod<<"\n";
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}