题目
题意: 给定长度为n的全排列,求一个求和。
思路: 首先看右边的式子,可以把x的求和放到后边去。这样的话,就是枚举所有区间[i,j] (1<=i<=n,i<=j<=n),i<=x<=j,px<=pk(i<=k<=j)。既然x在每个位置中出现,答案就是len*(len+1)/2,len是区间长度。因为区间中肯定有个相对大小,最小的数贡献是len,最大的数贡献是1。对于长度为len的区间,全排列n中有n-len+1个。这与全排列n怎么排的无关。
之后看左边的式子,全排列n的逆序对的期望是n*(n-1)/4。之后乘上n!的就是求和了。逆序对的期刊怎么求的呢?两个互逆的全排列的逆序对恰好是对方的正序对。(1,2,3,4,5) (5,4,3,2,1)。那么他们二者的逆序对之和就是一个序列的逆序对与正序对之和了,也就是n*(n-1)/2,平均到每个序列就是n*(n-1)/4
之后乘起来就行了
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
const int N = 1e5+10;
int n,m,k,T;
ll fac[N];
ll qpow(ll a,int k)
{
ll res = 1;
while(k)
{
if(k&1) res = res * a % mod;
a = a * a % mod;
k >>= 1;
}
return res;
}
ll ni(int x)
{
return qpow(x,mod-2);
}
void solve()
{
ll ans = 0;
cin>>n;
for(int i=1;i<=n;++i)
{
ll l = i*(i+1)%mod*ni(2)%mod;
ll r = n-i+1;
ll tmp = l*r%mod;
ans = (ans+tmp)%mod;
}
ll tmp = fac[n]*n%mod*(n-1)%mod*ni(4)%mod;
ans = (ans + tmp) % mod;
cout<<ans<<"\n";
}
signed main(void)
{
fac[0] = 1;
for(int i=1;i<N;++i) fac[i] = fac[i-1]*i%mod;
cin>>T;
while(T--)
solve();
return 0;
}