出题人的手环

链接: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。
题意:中文题
思路:计算出原始序列的逆序对(sum),转换后的通过观察我们可以得出将一个数移到序列最后它的逆序对变化为sum=sum+序列中大于a[1]的数-序列中小于a[1]的数。
代码:
#include<bits/stdc++.h>
#define mod 1000000007
using namespace std;
const int maxn=2e5+5;
int n;
int t[maxn],c[maxn],pmin[maxn],pmax[maxn];
vector<int> v,nv;
int getid(int x){
    return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
int lowbit(int x){
    return x&(-x);
}
void add(int x){
    while(x<=n){
        c[x]++;
        x+=lowbit(x);
    }
}
int query(int x){
    int ans=0;
    while(x>0){
        ans+=c[x];
        x-=lowbit(x);
    }
    return ans;
}
int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&t[i]);
        v.push_back(t[i]);
        nv.push_back(t[i]);
    }
    sort(v.begin(),v.end());
    sort(nv.begin(),nv.end());
    for(int i=0;i<n;i++){
        int u=lower_bound(v.begin(),v.end(),t[i])-v.begin();//第一个大于等于t[i]的数
        //cout<<u<<endl;
        if(v[u]==t[i]){
            int vi=upper_bound(v.begin(),v.end(),t[i])-v.begin();
            pmin[i]=u;
            pmax[i]=(n-vi);//cout<<pmin[i]<<" "<<pmax[i]<<endl;
        }else{
            pmin[i]=u;
            pmax[i]=(n-u);
        }

    }
    v.erase(unique(v.begin(),v.end()),v.end());
    long long sum=0;
    for(int i=0;i<n;i++){
        int u=getid(t[i]);
        add(u);
        sum+=(i+1)-query(u);
    }
    cout<<sum<<endl;
    long long ans=sum;
    for(int i=0;i<n-1;i++){
        sum=(sum+pmax[i]+mod-pmin[i])%mod;
        cout<<sum<<endl;
        ans=(ans*sum)%mod;
    }
    printf("%lld
",(ans+mod)%mod);
    return 0;
}


 
 
原文地址:https://www.cnblogs.com/liuzuolin/p/10828777.html