牛客练习赛D出题人的手环(树状数组+离散化+逆序数)

链接: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;
}

猜你喜欢

转载自blog.csdn.net/lanshan1111/article/details/86550142
今日推荐