链接:https://ac.nowcoder.com/acm/contest/358/D
来源:牛客网
题目描述
出题人的妹子送了出题人一个手环,这个手环上有 n 个珠子,每个珠子上有一个数。
有一天,出题人和妹子分手了,想把这个手环从两个珠子间切开,并按顺时针顺序展开成一条链。
可以发现,这条链一共有 n 种可能性。求这 n 种可能性的逆序对数之积模 1000000007。
输入描述:
第一行一个数 n,表示珠子个数。 接下来一行 n 个数,以顺时针顺序给出每个珠子上的整数
输出描述:
一个数,表示答案。
示例1
输入
4 1 3 2 3
输出
24
说明
一共有 4 种方式: 1 3 2 3;3 1 3 2;2 3 1 3;3 2 3 1; 逆序对数分别为 1,3,2,4,积为 24。
备注:
n<=200000,-10^9<=珠子上的整数<=10^9。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mods=1000000007;
const int maxnn=200000+66;//最大元素个数
int n;//元素个数
ll c[maxnn],a[maxnn];//c[i]==A[i]+A[i-1]+...+A[i-lowbit(i)+1]
ll b[maxnn];
int lowbit(int i)
{
return i&(-i);
}
//返回A[1]+...A[i]的和
ll sum(int x){
ll sum = 0;
while(x){
sum += c[x];
x -= lowbit(x);
}
return sum;
}
//令A[i] += val
void add(int x, ll val){
while(x <= n){
c[x] += val;
x += lowbit(x);
}
}
int num[maxnn];
int main()
{
while(scanf("%d",&n)!=-1)
{
memset(c,0,sizeof(c));
memset(num,0,sizeof(num));
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
b[i]=a[i];
}
sort(b+1,b+n+1);
ll ans=0;
int sum1=1;
for(int i=n;i>0;i--)
{
int pos=lower_bound(b+1,b+n+1,a[i])-b;
num[pos]++;
ans=(ans+sum(pos-1))%mods;
add(pos,1);
}
ll sum=ans;
for(int i=1;i<n;i++)
{
int pos=lower_bound(b+1,b+n+1,a[i])-b;
ans=(ans+(n-pos-num[pos]+1)-(pos-1)+mods)%mods;
sum=(sum*ans)%mods;
}
cout<<sum<<endl;
}
return 0;
}