AT_arc154_e 题解

题面

更好的阅读体验

题目要求的就是对于每种操作方案得到的排列中,所有逆序对位置之差的和。

首先我们考虑对于一个确定的排列 \(p\),它对答案的贡献如何表示,对于第 \(i\) 位,每有一个 \(j<i\)\(p_j>p_i\) 时会产生 \(i\) 的贡献,同时每有一个 \(j>i\)\(p_j<p_i\) 时会产生 \(-i\) 的贡献,于是我们令第 \(i\) 位贡献为 \(f(i)\),那么 \(f(i)\) 可以表示为:

\[\begin{aligned} f(i)&=i(\sum\limits_{j=1}^i[p_j>p_i]-\sum\limits_{j=i+1}^n[p_j\le p_i])\\ &=i(i-\sum\limits_{j=1}^i[p_j\le p_i]-\sum\limits_{j=i+1}^n[p_j\le p_i])\\ &=i(i-\sum\limits_{j=1}^n[p_j\le p_i])\\ &=i^i-i\times p_i \end{aligned} \]

现在我们考虑如何统计所有方案的权值和,这里我们可以求 \(\sum_{i=1}^ni^2-i\times p_i\) 的期望值,然后再乘上方案数。这里前面的 \(i^2\) 求和是一个定值,因为无论排列如何变化,最终 \(1\)\(n\) 都会占满 \(1\)\(n\) 的位置。所以要求的就是 \(\sum_{i=1}^ni^2-\sum_{i=1}^n iE(p'_i)\)

关键在于求位置的期望值,看起来似乎很困难,但是细想一下,位置 \(i\) 如果被操作区间覆盖了,经过这一次操作到 \(j\) 的方案数应该是多少。

  • 如果 \(j>i\)\(min(i,n-j+1)\) 种方案。
  • 如果 \(j<i\)\(min(j,n-i+1)\) 种方案。
    我们把两种情况合并一下,得到方案数为 \(min(i,j,n-i+1,n-j+1)\)。所以 \(i\) 经过一次操作到 \(n-j+1\) 的方案数是一样的,也就相当于概率是一样的。所以对于任何一个位置,当它被操作区间覆盖时,最终位置的期望值都是\(\frac n2\),而不被覆盖时就会留在原地。现在就很好求了,位置 \(i\) 不被覆盖的概率为 \(1-\frac{2i(n-i+1)}{n(n+1)}\),那么 \(m\) 次操作都不被覆盖的概率就是 \(q=(1-\frac{2i(n-i+1)}{n(n+1)})^m\),则 \(E(p_i)=iq+\frac n2(1-q)\) ,这道题就做完了。

code

代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll fac[100]={1},sum[100],n=16;
inline ll rd()
{
	char c;ll f=1;
	while(!isdigit(c=getchar()))if(c=='-')f=-1;
	ll x=c-'0';
	while(isdigit(c=getchar()))x=x*10+(c^48);
	return x*f;
}
inline ll qp(ll x,ll y)
{
	ll res=1;
	while(y)
	{
		if(y&1) (res*=x)%=mod;
		(x*=x)%=mod,y>>=1;
	}
	return res;
}
ll C(ll n,ll m)
{
	ll s=1;
	for(int i=1;i<=m;i++) (s*=(n-i+1))%=mod;
	return s*qp(fac[m],mod-2)%mod;
}
ll ans(ll k)
{
	if(k<5) return 0;k-=5;
	n=min(16ll,k/2);
	for(int j=0;j<=n;j++)
		sum[j]=C(j+4,4)*C(k-2*j+10,10)%mod;
	k/=2;ll s=0;
	for(int j=1;j<=n;j++) (sum[j]+=sum[j-1])%=mod;
	if(k<=n) return (sum[k]+mod)%mod;
	for(int i=0;i<=n;i++)
	{
		ll s1=sum[i],s2=1;
		for(int j=0;j<=n;j++) if(j!=i)
			s1=s1*(k-j)%mod,s2=s2*(i-j)%mod;
		(s+=s1*qp(s2,mod-2)%mod)%=mod;
	}
	return (s+mod)%mod;
}
int main()
{
	for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod;
	for(ll t=rd();t--;) printf("%lld\n",ans(rd()));
	return 0;
}
posted @ 2025-03-31 20:17  Re_Star  阅读(17)  评论(0)    收藏  举报