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

链接:https://ac.nowcoder.com/acm/contest/358/D
来源:牛客网

题目:

出题人的妹子送了出题人一个手环,这个手环上有 n 个珠子,每个珠子上有一个数。

有一天,出题人和妹子分手了,想把这个手环从两个珠子间切开,并按顺时针顺序展开成一条链。

可以发现,这条链一共有 n 种可能性。求这 n 种可能性的逆序对数之积模 1000000007。

输入:

第一行一个数 n,表示珠子个数。
接下来一行 n 个数,以顺时针顺序给出每个珠子上的整数

输出:

一个数,表示答案。

分析:

n种情况无非是每次将第一个元素移到末尾,此时逆序数个数的变化为:当前逆序数总数 - 比 a[1] 小的数的个数 + 比 a[1] 大的个数

第一次的逆序数的总数可以用树状数组计算,但 a[i] 范围太大,n 比较小,于是先将 a[i] 排序后离散化,再处理出比每个数大的数的个数和比它小的数的个数

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MOD  = 1e9+7;
const int MAXN = 2e5+55;
LL a[MAXN],b[MAXN],c[MAXN],num1[MAXN],num2[MAXN],n;
inline int lowbit(int x)
{
    return x & (-x);
}
void updata(int pos,int val)
{
    while(pos <= n)
    {
        a[pos] += val;
        pos += lowbit(pos);
    }
}
int query(int pos)
{
    int res = 0;
    while(pos > 0)
    {
        res += a[pos];
        pos -= lowbit(pos);
    }
    return res;
}
int main()
{
    cin>>n;
    for(int i = 0; i < n; ++i)
    {
        cin>>b[i];
        c[i] = b[i];
    }
    sort(c,c+n);
    LL sum = 0;                                 //总的逆序数对
    for(int i = 0; i < n; ++i)
    {
        int pos1 = lower_bound(c,c+n,b[i]) - c;
        int pos2 = upper_bound(c,c+n,b[i]) - c;
        num1[i] = pos1;                         //比b[i]小的总个数
        num2[i] = n - pos2;                     //比b[i]大的总个数
        sum += pos1 - query(pos1);              
        updata(pos1+1,1);
    }
    LL res = sum % MOD;
    for(int i = 0; i < n-1; ++i)                //注意最后一个数不能再算了
    {
        sum = ((sum - num1[i] + num2[i])%MOD + MOD) % MOD;
        res = (res * sum) % MOD;
    }
    cout<<res;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41157137/article/details/86549999
今日推荐