对于排列$\{P\}$,按照如下方式构造排列$\{Q\}$:
对所有$i$建边$(i,P_{i})$,假设图中有$m$个环且第$i$个环上的点(沿着边)依次构成序列$\{h_{i}\}$
不妨强制$h_{i,1}\le h_{i,j}$且$h_{1,1}>h_{2,1}>...>h_{m,1}$,则$\{Q\}=\sum_{i=1}^{m}\{h_{i}\}$(指拼接)
从排列$\{Q\}$的角度考虑此问题,那么$k$即为其中长度为奇数的极长连续上升子序列个数
另一方面,不难证明排列$\{P\},\{Q\}$一一对应,因此也即统计所有排列的上述信息
进一步的,将排列中的极长连续上升子序列从前往后标记为$AB$,剩下的位置标记为$C$
确定上述标记后,$k$即为其中$C$的个数,同时限制即$A$小于其下一个数且$C$在末尾或大于其下一个数
(注意并不关心偶数长度的序列,因此不需要考虑$BA$和$BC$之间的大小关系)
根据限制,在所有$B$之后断开,断开后每一段序列限制是独立的,且总是形如若干个$C$(允许为0)$+(AB)$
另外,如果没有$AB$显然必然是最后一段,这可以在最后处理(即以下强制存在$AB$)
在此基础上,进行dp计算,令$f_{i}$表示前$i$个位置的答案,转移即$f_{i}=\sum_{j=2}^{i}{i\choose j}(j-1)W^{j-2}f_{i-j}$
结合最后一段$C$,最终答案即$\sum_{i=0}^{n}{n\choose i}W^{i}f_{n-i}$,显然可以$o(n)$计算
关于上述dp式子的计算,可以使用cdq分治+NTT做到$o(n\log^{2}n)$,或使用生成函数进一步优化
具体的,定义$F(x)=\sum_{i\ge 0}\frac{f_{i}}{i!}x^{i}$,代入转移即
$$
\begin{array}{ll}
F(x)
&=\sum_{i\ge 0}\frac{\sum_{j=2}^{i}{i\choose j}(j-1)W^{j-2}f_{i-j}}{i!}x^{i}\\
&=1+\sum_{j\ge 2}\frac{(j-1)W^{j-2}}{j!}\sum_{i\ge j}\frac{f_{i-j}}{(i-j)!}x^{i}\\
&=1+\sum_{j\ge 2}\frac{(j-1)W^{j-2}}{j!}x^{j}F(x)
\end{array}
$$
简单移项,解得$F(x)=\frac{1}{1-\sum_{j\ge 2}\frac{(j-1)W^{j-2}}{j!}x^{j}}$,那么多项式求逆即可
时间复杂度为$o(n\log n)$,可以通过

1 #include
2 using namespace std;
3 #define N 200005
4 #define mod 998244353
5 #define ll long long
6 int n,W,ans,mi[N],inv[N],rev[N<<2];
7 struct Poly{
8 vector<int>a;
9 Poly(){
10 a.clear();
11 }
12 }a;
13 int qpow(int n,int m){
14 int s=n,ans=1;
15 while (m){
16 if (m&1)ans=(ll)ans*s%mod;
17 s=(ll)s*s%mod,m>>=1;
18 }
19 return ans;
20 }
21 void ntt(Poly &a,int n,int p=0){
22 for(int i=0;i)
23 if (i<rev[i])swap(a.a[i],a.a[rev[i]]);
24 for(int i=2;i<=n;i<<=1){
25 int s=qpow(3,(mod-1)/i);
26 if (p)s=qpow(s,mod-2);
27 for(int j=0;ji)
28 for(int k=0,ss=1;k<(i>>1);k++,ss=(ll)ss*s%mod){
29 int x=a.a[j+k],y=(ll)a.a[j+k+(i>>1)]*ss%mod;
30 a.a[j+k]=(x+y)%mod,a.a[j+k+(i>>1)]=(x-y+mod)%mod;
31 }
32 }
33 if (p){
34 int s=qpow(n,mod-2);
35 for(int i=0;imod;
36 }
37 }
38 Poly mul(Poly a,Poly b,int n){
39 int m=1;
40 while (m1;
41 m<<=1,a.a.resize(m),b.a.resize(m);
42 for(int i=n;i0;
43 for(int i=0;i>1]>>1)+((i&1)*(m>>1));
44 ntt(a,m),ntt(b,m);
45 for(int i=0;imod;
46 ntt(a,m,1),a.a.resize(n);
47 return a;
48 }
49 Poly get_inv(Poly a,int n){
50 Poly ans;
51 if (n==1){
52 ans.a.push_back(qpow(a.a[0],mod-2));
53 return ans;
54 }
55 Poly s=get_inv(a,(n+1>>1));
56 ans=mul(s,a,n);
57 for(int i=0;imod;
58 ans.a[0]=(ans.a[0]+2)%mod;
59 return mul(ans,s,n);
60 }
61 int main(){
62 scanf("%d%d",&n,&W);
63 mi[0]=inv[0]=inv[1]=1;
64 for(int i=1;i1]*W%mod;
65 for(int i=2;imod;
66 for(int i=1;i1]*inv[i]%mod;
67 for(int i=0;i<=n;i++){
68 if (!i)a.a.push_back(1);
69 if (i==1)a.a.push_back(0);
70 if (i>=2){
71 int s=(ll)(i-1)*mi[i-2]%mod*inv[i]%mod;
72 a.a.push_back((mod-s)%mod);
73 }
74 }
75 a=get_inv(a,n+1);
76 for(int i=0;i<=n;i++)ans=(ans+(ll)inv[i]*mi[i]%mod*a.a[n-i])%mod;
77 for(int i=1;i<=n;i++)ans=(ll)ans*i%mod;
78 printf("%d\n",ans);
79 return 0;
80 }