给定 n,m 和一个 n 的排列 P。重复进行如下操作 m 次:
- 选定 1≤i≤j≤n,并将 Pi,Pi+1,..,Pj 翻转。
对于所有 (2n(n+1))m 种方案,计算 ∑i<j[Pi>Pj](j−i) 的值的和。
1≤n,m≤2×105。
考虑拆开 ∑i<j[Pi>Pj](j−i):
i<j∑[Pi>Pj](j−i)=i∑i×(j<i∑[Pi<Pj]−j>i∑[Pi>Pj])=i∑i×(i−j<i∑[Pi≥Pj]−j>i∑[Pi>Pj])=i∑i×(i−j∑[Pi≥Pj])=i∑i×(i−Pi)=i∑i2−i∑iPi
那么只要求出 i∑iPi 的和即可。
注意到操作只和位置相关,Pi 的和不太好求,那么不妨转而求 Qi 表示 Pi 最后去的位置(P 的逆排列),那么 i∑iPi=i∑QiPi。
发现 Qi 还是不好求,这时候你突然灵光一闪就能想到,其实可以求 Si 表示 Qi 的期望,最后再乘上 (2n(n+1))m。
注意到 Si 是好求的。具体的,Pi 一旦被某次操作覆盖到,那么它去往 j 和去往 n−j+1 的概率是一样的,因为你总能构建出双射。
那么答案即为 (2n(n+1))m(i∑i2−i∑SiPi)。
代码如下:
#include <iostream>
#include <cstdio>
using namespace std;
const int S=200005,p=998244353,inv2=(p+1)/2;
int n,m,a[S];
inline int qpow(int x,int y)
{
int res=1;
for(;y>0;y>>=1,x=1ll*x*x%p) res=y&1?1ll*res*x%p:res;
return res;
}
inline void add(int &x,int y)
{
x+=y;
if(x>=p) x-=p;
}
inline int calc(int n)
{
return 1ll*(n+1)*n/2%p;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
int sm=0;
for(int i=1;i<=n;i++)
{
add(sm,1ll*i*i%p);
int nc1=1ll*(calc(i-1)+calc(n-i))*qpow(calc(n),p-2)%p;
int ncov=qpow(nc1,m);
int si=0;
add(si,1ll*i*ncov%p);
add(si,1ll*(n+1)*inv2%p*(p+1-ncov)%p);
add(sm,p-1ll*si*a[i]%p);
}
sm=1ll*sm*qpow(calc(n),m)%p;
printf("%d\n",sm);
return 0;
}