牛客手速月赛60 F(鼠鼠输)

题目
题意: 给定长度为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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值