排队(牛客小白月赛61)

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
 

The__Flash 打游戏太投入了,把 PLMM 晾在了一边。为了弥补 PLMM,The__Flash 带着 PLMM 和小喵去看电影。

电影院人山人海,队伍排成一条长长的线,两人一喵只能乖乖排队。队伍长度为 nnn,个体按照队头到队尾的顺序依次编号为 1,2,...,n1,2,...,n1,2,...,n,其中第 iii 个个体的身高为 aia_iai​。PLMM 见状想要出题考验一下 The__Flash。

一个长度为 nnn 的序列 aaa 的逆序对个数定义为满足 ai>aj (1≤i<j≤n)a_i>a_j \, (1 \leq i < j \leq n)ai​>aj​(1≤i<j≤n) 的不同 (i,j)(i,j)(i,j) 的对数,(i1,j1)(i_1,j_1)(i1​,j1​) 与 (i2,j2)(i_2,j_2)(i2​,j2​) 不同当且仅当 i1≠i2i_1 \not= i_2i1​​=i2​ 或 j1≠j2j_1 \not= j_2j1​​=j2​。

nnn 个个体总共有 n!n!n! 种排队方式,记 Pi(a)P_i(a)Pi​(a) 表示序列 aaa 的第 iii 种排队方式,cnt(Pi(a))cnt(P_i(a))cnt(Pi​(a)) 表示 PiP_iPi​ 的逆序对个数。PLMM 想知道 ∑i=1n!cnt(Pi(a))\sum_{i=1}^{n!}{cnt(P_i(a))}∑i=1n!​cnt(Pi​(a)),由于 The__Flash 傻乎乎的,所以请你帮他回答 PLMM 的问题。

输入描述:

第一行输入一个整数 n (1≤n≤105)n\,(1 \leq n \leq 10^5)n(1≤n≤105)。

第二行输入 nnn 个整数表示 a1,a2,⋯ ,an (1≤ai≤105)a_1,a_2,\cdots,a_n\,(1 \leq a_i \leq 10^5)a1​,a2​,⋯,an​(1≤ai​≤105)。

输出描述:

输出一个整数表示答案,由于结果可能太大,因此你只需要输出结果对 109+710^9+7109+7 取模之后的结果。

示例1

输入

复制3 1 2 3

3
1 2 3

输出

复制9

9

思路:算全排列中一共有多少个逆序对,那我们就分别算每个逆序对对总数的贡献

对于两个不相等的数a和b,在全排列中只有两种情况,要么a在前,要么b在前,且这两种情况的排列的数量相等

假设a在前b在后,那么我们就算出含有这个逆序对的排列的个数

对于a来说有n个选择,对于b来说有n-1个选择,但是a在b的前面占所有情况的一半,剩下的(n-2)个数全排列

那么a在b前面的排列就有n*(n-1)/2*(n-2)!个

那么我们只需要算出来逆序对的数量乘上面的柿子就行了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
const int N=1e5+10;
const ll mod=1e9+7;
ll f[N];
ll a[N];
ll ksm(ll a,ll b,ll p){
	ll ans=1%p;
	while(b){
		if(b&1)ans=ans*a%p;
		a=a*a%p;
		b>>=1;
	}
	return ans;
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	sort(a+1,a+1+n);
	f[0]=1;
	for(int i=1;i<=n;i++){
		f[i]=f[i-1]*i%mod;
	}
	ll ans=0;
	for(int i=1;i<=n;i++){
		int id=lower_bound(a+1,a+1+n,a[i])-a-1;
		ans+=id;
	}
	ll con=ans*n%mod*(n-1)%mod*f[n-2]%mod*ksm(2,mod-2,mod)%mod;
	cout<<con<<endl;
	//cout<<ans<<endl;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值