题解:
最长连续序列不能相交,那么只有包含关系。
一个区间包含若干区间,我们可以先把这些区间内部确定,然后再把这些区间缩为一个点(因为连续),然后就只用解决长度为 n n n且连续区间一定包含 p n p_n pn的方案数(否则就与 L i L_i Li矛盾了)。令 b p i = i b_{p_i}=i bpi=i,相当于是所有连续区间必须包含最大值,也就相当于必须包含最小值。
记序列长度为
n
n
n的答案为
f
n
f_n
fn,考虑加入最大值:
1.加入之前的序列是合法的。 这时候所有的连续区间包含1,我们加入最大值只用保证与
n
−
1
n-1
n−1不相邻即可。
2.加入之前的序列不合法。 此时考虑极长的不包含1的连续区间,这样的区间不可能有两个,否则加入之后依然不合法。 设其长度为
l
l
l,我们要保证加入n之后这个区间变得不连续,首先他的最大值不能为
n
−
1
n-1
n−1,其次删除这个n之后两边没有连续区间,他们串起来就相当于
f
l
+
1
f_{l+1}
fl+1。 我们可以枚举这个l,然后缩成一个点,内部方案数为
f
l
+
1
f_{l+1}
fl+1,外部方案数为
f
n
−
l
(
n
−
l
−
2
)
f_{n-l} (n-l-2)
fn−l(n−l−2)。 减2的原因是这个区间不能从1开始,也不能包含最大值。
于是得到递推式: f n = ( n − 2 ) f n − 1 + ∑ i = 2 n − 3 f n − l ( n − l − 2 ) f l + 1 f_n = (n-2) f_{n-1} + \sum_{i=2}^{n-3}f_{n-l}(n-l-2)f_{l+1} fn=(n−2)fn−1+∑i=2n−3fn−l(n−l−2)fl+1。 分治FFT即可。
#include <bits/stdc++.h>
using namespace std;
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
inline void W(int x) {
static int buf[50];
if(!x) {putchar('0'); return;}
if(x<0) {putchar('-'); x=-x;}
while(x) {buf[++buf[0]]=x%10; x/=10;}
while(buf[0]) {putchar(buf[buf[0]--]+'0');}
}
const int N=5e4+50,mod=998244353,G=3;
inline int add(int x,int y) {return (x+y>=mod) ? (x+y-mod) : (x+y);}
inline int dec(int x,int y) {return (x-y<0) ? (x-y+mod) : (x-y);}
inline int mul(int x,int y) {return (long long)x*y%mod;}
inline int qpw(int a,int b,int rs=1) {for(;b;b>>=1,a=mul(a,a)) if(b&1) rs=mul(rs,a); return rs;}
int n,k,f[N];
int g[N*8],h[N*8],w[N*8],pos[N*8];
inline void init(int nn) {
nn*=2;
for(k=1;k<=nn;k<<=1);
for(int i=1;i<k;i++) pos[i]=(i&1) ? (pos[i>>1]>>1)^(k>>1) : (pos[i>>1]>>1);
memset(g,0,sizeof(int)*k);
memset(h,0,sizeof(int)*k);
}
inline void dft(int *a) {
for(int i=1;i<k;i++) if(pos[i]>i) swap(a[pos[i]],a[i]);
for(int bl=1;bl<k;bl<<=1) {
int tl=bl<<1, wn=qpw(G,(mod-1)/tl);
w[0]=1; for(int i=1;i<bl;i++) w[i]=mul(w[i-1],wn);
for(int bg=0;bg<k;bg+=tl)
for(int j=0;j<bl;j++) {
int &t1=a[bg+j], &t2=a[bg+j+bl], t=mul(t2,w[j]);
t2=dec(t1,t); t1=add(t1,t);
}
}
}
inline void mul(int *a,int *b) {
dft(a); dft(b);
for(int i=0;i<k;i++) a[i]=mul(a[i],b[i]);
dft(a); const int inv=qpw(k,mod-2);
for(int i=0;i<k;i++) a[i]=mul(a[i],inv);
reverse(a+1,a+k);
}
inline void solve(int l,int r) {
if(l==r) {
if(l==3) f[l]=2;
else f[l]=add(f[l],mul(l-2,f[l-1]));
return;
}
int mid=(l+r)>>1; solve(l,mid);
init(mid-l+1);
for(int i=l;i<=mid;i++) g[i-l]=f[i], h[i-l]=mul(f[i],i-2);
mul(g,h);
for(int i=mid+1;i<=r;i++) if(i+1-2*l<k) f[i]=add(f[i],g[i+1-2*l]);
if(l!=3) {
init(r-l+1);
for(int i=l;i<=mid;i++) g[i-l]=f[i];
for(int i=3;i+l<=r+1;i++) h[i-3]=mul(f[i],i-2);
mul(g,h);
for(int i=mid+1;i<=r;i++) if(i-2-l<k) f[i]=add(f[i],g[i-2-l]);
init(r-l+1);
for(int i=l;i<=mid;i++) g[i-l]=mul(f[i],i-2);
for(int i=3;i+l<=r+1;i++) h[i-3]=f[i];
mul(g,h);
for(int i=mid+1;i<=r;i++) if(i-2-l<k) f[i]=add(f[i],g[i-2-l]);
}
solve(mid+1,r);
}
int l[N],stk[N];
vector <int> vl[N];
inline int calc(int l,int r) {
vl[l].pop_back();
int tot=r-l+1, ans=1;
for(int i=l;i<=r;i++) if(vl[i].size()) {
tot-=vl[i].back()-i;
int r=vl[i].back();
ans=mul(ans,calc(i,vl[i].back()));
i=r;
}
return mul(ans,f[tot]);
}
int main() {
int T=rd(); n=rd();
solve(3,n);
f[1]=1; f[2]=2;
while(T--) {
int ans=1;
for(int i=1;i<=n;i++) l[i]=i-rd()+1, vl[i].clear();
if(l[n]!=1) {puts("0"); continue;}
int tag=1;
for(int i=n;i>=1;i--) if(l[i]!=i) vl[l[i]].push_back(i);;
int top=0;
for(int i=1;i<=n;i++) {
for(auto j:vl[i]) stk[++top]=j;
if(l[i]!=i) {
if(stk[top]!=i) {tag=0; break;}
else --top;
}
if(!tag) break;
}
if(!tag) {puts("0"); continue;}
for(int i=1;i<=n;i++) reverse(vl[i].begin(),vl[i].end());
W(calc(1,n)); putchar('\n');
}
}