# 逆序數對&加總
## 題目敘述
>在一個長度為N的正整數序列$A$中,找出有多少個數對滿足 $Ai>Aj$ 且 $i<j$,並加總每個逆序數對中的兩個數的和
## 解題思路
### 1.Merge Sort
>$dc(l,r)$ 表示從 $Al$ 到 $Ar$ 中的逆序數對的總和
>
>$dc(l,r)=dc(l+m)+dc(m+1,r)+$橫跨左右的逆序數對總和
#### 如何求橫跨左右的逆序數對
>在合併左右序列時,比較兩序列最小的元素(因為分治的關係,兩序列已經是有序的)
>
>若右邊的比較小,代表這是一個逆序數對,且之後每一個左序列的元素皆可以跟這個元素形成逆序數對(因為有序)
```cpp=
#define ll long long
int num[1000005],tmp[1000005];
int l,r,m;
m=(l+r)/2;
ll ans=0;
ll i=l,j=m+1,sl=0,sm=0;
//sm:目前取自右序列中的數值總和
//sl:目前取自右序列中的數的個數
for(int a=l;a<=r;a++){
if(i==(m+1)){ //左序列已取完
tmp[a]=num[j];
j++;
}
else if(j==(r+1)){ //右序列已取完
tmp[a]=num[i];
ans+=num[i]*sl+sm;
i++;
}
else if(num[i]<num[j]){ //左序列最小的元素較小
tmp[a]=num[i];
ans+=num[i]*sl+sm;
i++;
}
else{ //右序列最小的元素較小,更新sl及sr
sl++;
sm+=num[j];
tmp[a]=num[j];
j++;
}
}
for(int a=l;a<=r;a++) num[a]=tmp[a];
```
#### 完整的程式碼
``` cpp=
#include<iostream>
#define ll long long
using namespace std;
int num[1000005],tmp[1000005];
ll dc(int l,int r){
if(l==r) return 0;
if((l+1)==r){
if(num[l]>num[r]){
swap(num[l],num[r]);
return (num[l]+num[r]);
}
return 0;
}
ll ans=0;
int m=(l+r)/2;
ans+=dc(l,m)+dc(m+1,r);//遞迴+分治
ll i=l,j=m+1,sl=0,sm=0;
//sm:目前取自右序列中的數值總和
//sl:目前取自右序列中的數的個數
for(int a=l;a<=r;a++){
if(i==(m+1)){ //左序列已取完
tmp[a]=num[j];
j++;
}
else if(j==(r+1)){ //右序列已取完
tmp[a]=num[i];
ans+=num[i]*sl+sm;
i++;
}
else if(num[i]<num[j]){ //左序列最小的元素較小
tmp[a]=num[i];
ans+=num[i]*sl+sm;
i++;
}
else{ //右序列最小的元素較小,更新sl及sr
sl++;
sm+=num[j];
tmp[a]=num[j];
j++;
}
}
for(int a=l;a<=r;a++) num[a]=tmp[a];
return ans;
}
int main(){
int N;
cin>>N;
for(int i=1;i<=N;i++) cin>>num[i];
cout<<dc(1,N)<<endl;
}
```
### 2.BIT
>將原本的序列從$1$到$N$編號,由大到小排序後,從第一項(最大的那項)開始往後,並記錄現在比某個編號小的數有幾個,即$a[i]=$ 編號小於$i$的數有幾個,由於已經排序好了,因此到目前為止所記錄的數都會比自己大,編號比自己小的數也就可以與自己形成逆序數對
#### BIT的部分
```cpp=
struct BIT{
ll a[1000005];
int n;
void ini(int _n){ //初始BIT陣列
n=_n;
memset(a,0,sizeof(a));
}
void add(ll x,ll v){ //更新BIT陣列,在每個有包含x的區間加上v
while(x<=n){
a[x]+=v;
x+=(x)&(-x); //x&(-x)就是x的lowbit,也就是x在二進位制中最小的1
}
}
ll ask(ll x){ //詢問小於等於x的區間
ll r=0;
while(x>0){
r+=a[x];
x-=(x)&(-x);
}
return n;
}
}
```
#### 完整程式碼
>用pair儲存每個數的初始編號及數值
```cpp=
#include<iostream>
#include<vector>
#define ll long long
#define F first
#define S second
bool cmp(pair<ll,ll> a , pair<ll,ll> b){ //自訂sort比較函式
if(a.F!=b.F) return a.F>b.F; // 若數值不一樣,回傳較大的
return a.S>b.S; // 否則就回傳編號較大的,因為若數值相同便不能成為逆序數對
}
struct BIT{
ll a[1000005];
int n;
void ini(int _n){ //初始BIT陣列
n=_n;
memset(a,0,sizeof(a));
}
void add(ll x,ll v){ //更新BIT陣列,在每個有包含x的區間加上v
while(x<=n){
a[x]+=v;
x+=(x)&(-x); //x&(-x)就是x的lowbit,也就是x在二進位制中最小的1
}
}
ll ask(ll x){ //詢問小於等於x的區間
ll r=0;
while(x>0){
r+=a[x];
x-=(x)&(-x);
}
return n;
}
}cnt,bit; // cnt記錄的是個數 bit記錄的是數值總和
int main() {
int n;
cin>>n;
vector<pair<ll,ll> > v(n+5);
for(int i=0;i<n;i++){
cin>>v[i].F;
v[i].S=i+1; //編號從1開始,若從0開始,lowbit將永遠都是0
}
bit.ini(n);
cnt.ini(n);
sort(v.begin(),v.end(),cmp);
ll ans=0;
for(int i=0;i<n;i++){
ans += bit.ask(v[i].S-1) + // 數值大於且編號小於此數的數值總和
v[i].F*cnt.ask(v[i].S-1); // 數值大於且編號小於此數的元素個數
bit.add(v[i].S,v[i].F); // 更新數值
cnt.add(v[i].S,1); // 更新個數
}
cout<<ans<<"\n";
return 0;
}
```