给定 ,考虑对某个 的排列 (标号 )做如下操作:
- 从 到 枚举 ,把 拿出来升序排序再放回去;
给定一个 的排列 ,求有多少个 满足操作完后会变成 。
,。
由于 很大,所以猜测操作很多次是没用的。
观察到若 则后 次操作相当于拉着前 大值在转圈,所以这些操作是没用的,仅需把前 大值复位即可归约到 的情况。
不难发现 的情况可以通过删掉操作没影响到的一段后缀来归约到 的情况,所以仅需讨论 情况下的做法。
不难发现,若 则 一定填入 ,否则:
-
若 是前缀最大值,则其可以找 中随便一个未填数的位置填入,有 种方案;
-
若 不是前缀最大值,则 一定填入 ,证明如下:
若 则证明完毕,否则找到 前面最靠后的 的 ,则 一定不能填入 。
观察到 ,所以 一定填入 , 原本可以填入 ,可 被占用,所以它只能填入 。这样一直循环进行,最终 均被占用,所以 仅能填入 。
Q.E.D.
那么设 有 个前缀最大值,答案即为 ,最后的阶乘是因为最后一段的尾巴可以乱放。
时间复杂度 ,注意 的判断,代码如下:
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
const int S=300005,p=998244353;
int n,m,k,a[S];
int b[S],c[S];
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
if(k>n-m+1)
{
int lft=k-(n-m+1);
int beg=((n-m+1)+lft)%n;
for(int i=0;i<m-1;i++) b[i]=a[(beg+i)%n];
int siz=n-m+1;
for(int i=0;i<siz;i++) c[i]=a[(beg+m-1+i)%n];
for(int i=0;i<siz;i++) a[i]=c[((i-lft)%siz+siz)%siz];
for(int i=0;i<m-1;i++) a[siz+i]=b[i];
k=n-m+1;
}
for(int i=0;i<n;i++) b[i]=a[i];
sort(b+k-1,b+k-1+m);
for(int i=k-1;i<=k-1+m-1;i++)
{
if(a[i]<a[k-1]||a[i]!=b[i]) return puts("0"),0;
}
int ans=1;
for(int i=0;i<k;i++)
{
if(i==0||a[i]>a[i-1]) ans=1ll*ans*m%p;
else a[i]=a[i-1];
}
for(int i=1;i<m;i++) ans=1ll*ans*i%p;
printf("%d\n",ans);
return 0;
}