牛客練習賽38 D 出題人的手環
阿新 • • 發佈:2019-01-28
順序 bound memset += bool ont sort txt contest
鏈接
[https://ac.nowcoder.com/acm/contest/358/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。
分析
首先我們知道用樹狀數組求,逆序數
那麽這題由於數據範圍是-10^9<=珠子上的整數<=10^9。
開一個數組必然是不夠的,所以首先離散化一下,就可以求出第一次的逆序數
那麽每次變化一個順序,可以把第一個元素弄到最後,那麽逆序數會變為多少呢?
首先對於某個數,求出小於它的數的個數
int pos1 = lower_bound(d,d+n,a[i+1].va) - d; x[i] = pos1; //比b[i]小的總個數
以及大於它的數的個數。
int pos2 = upper_bound(d,d+n,a[i+1].va) - d;
y[i] = n - pos2; //比b[i]大的總個數
這裏用了lower_bound和upper_bound,
for(int i = 0; i < n; ++i) { int pos1 = lower_bound(d,d+n,a[i+1].va) - d; int pos2 = upper_bound(d,d+n,a[i+1].va) - d; x[i] = pos1; //比b[i]小的總個數 y[i] = n - pos2; //比b[i]大的總個數 //cout<<x[i]<<‘ ‘<<y[i]<<endl; }
後面遍歷剩下乘積取模即可
代碼
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=1e9+7;
const int N=2e5+10;
int n;
int b[N];
int c[N];
int d[N];
int x[N];
int y[N];
struct node{
int va,pos;
}a[N];
bool cmp(node x,node y){
return x.va<y.va;
}
void update(int i,int va){
for(int j=i;j<=n;j+=j&-j)
c[j]+=va;
}
int getsum(int x){
int ans=0;
for(int i=x;i;i-=i&-i)
ans+=c[i];
return ans;
}
int main(){
//freopen("in.txt","r",stdin);
while(cin>>n){
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++){
cin>>a[i].va;
d[i-1]=a[i].va;
a[i].pos=i;
}
sort(d,d+n);
for(int i = 0; i < n; ++i)
{
int pos1 = lower_bound(d,d+n,a[i+1].va) - d;
int pos2 = upper_bound(d,d+n,a[i+1].va) - d;
x[i] = pos1; //比b[i]小的總個數
y[i] = n - pos2; //比b[i]大的總個數
//cout<<x[i]<<‘ ‘<<y[i]<<endl;
}
sort(a+1,a+n+1,cmp);
int cnt=1;
for(int i=1;i<=n;i++){
if(i!=1&&a[i].va!=a[i-1].va)
cnt++;
b[a[i].pos]=cnt;
}
ll sum=0;
for(int i=1;i<=n;i++){
update(b[i],1);
sum+=i-getsum(b[i]);
sum%=mod;
}
//cout<<sum<<endl;
ll ans=sum;
for(int i=0;i<n-1;i++){
sum=((sum-x[i]+y[i])%mod+mod)%mod;
ans=ans*sum%mod;
}
cout<<ans<<endl;
}
return 0;
}
牛客練習賽38 D 出題人的手環