鏈接:https://www.nowcoder.com/acm/contest/143/D
來源:牛客網
Kanade has an even number n and a permutation b of all of the even numbers in [1,n]
Let a denote an array [1,3,5....n-1] , now you need to find a permutation of [1,n] satisfy both a and b are subsequence of it and minimize the number of inverse pair of it.
輸入描述:
The first line has a positive even integer n The second line has n/2 positive even integers b[i]
輸出描述:
Output the number of inverse pair of the permutation you find.
示例1
輸入
6 2 6 4
輸出
2
說明
[1,2,3,5,6,4]
題意:
給定一個【1,n】裏所有偶數的排列,b,其中n爲偶數,現在有數組a = 【1,3,5,7,....n-1】,現在要求歸併a,b使得逆序對數量最少。
思路:
例如 8 6 4 2
我們考慮每個奇數如何放置。
對於7來說,我們考慮比7大的數,那麼就只有8一個,如果我們把7放在8前面,那麼7將不會與比她大的數產生逆序。
可是我們還要考慮她和比她小的數產生逆序,那麼考慮8的後面,若有比7小的數,那麼逆序++,並且由7產生的逆序最多有一個,因爲我們總可以把7放在最後。
現在考慮5,比5大的數就有兩個了,那麼由5產生的逆序最多爲兩個。我們考慮 8 6 的後面,如果沒有比5小的數,可以把5放在8,6前面,逆序爲0,若果有一個逆序爲1,否則取最多2.
由上面的分析可以看出,對於每個奇數,我們考慮比她大的偶數的個數假設爲x,那麼該奇數最多產生x對逆序,如果,比他大的數可以向後匹配比這個奇數小的數,假設可以匹配出y對來,那麼該奇數逆序的貢獻爲min(x,y);
對於 8 6 4 2 來說考慮5 (8,4),(6,2) 兩對,8,6有兩個,故而 x=y=2;
那麼如何統一計算結果呢????
如果單單考慮5, 遇到8>5 我們可以先存起來,6>5存起來,4<5 取出來8湊一對,2<5取出6湊一對。
設最終逆序爲ans = 0;
若統一考慮所有情況。我們可以考慮優先隊列來存,
8入隊 8 並不小於對中最大值繼續
6入隊 6 < 8 考慮(8,6)這個對可以使7的逆序加一 ans++
又因爲對於7來說8只能向後匹配一次已經用了,可是對於小於6的數來說(8,6)的匹配對他們沒有任何影響,那 8 該何去何從 ? 很簡單,只要扔掉8,加入一個6就好了,6 肯定不會對7的結果產生影響了,但是可以對剩下的 產生影響。
此時隊列就有 6 6,兩個6
4入隊 4 < 6 一個6出隊5這個逆序加一 ans++;
2入隊 2 < 6 一個6出隊3,5逆序加一 ans+=2;
emmmmm 代碼就很簡單了,,,
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+7;
int a[maxn],tree[maxn];
int n;
int lowbit(int x)
{
return x&(-x);
}
void add(int x,int v)
{
for(;x <= n; x+=lowbit(x))
tree[x]+=v;
}
int sum(int x)
{
int ans = 0;
for(;x >= 1; x-=lowbit(x))
ans+=tree[x];
return ans;
}
int main()
{
scanf("%d",&n);
for(int i = 0; i < n/2; i++)
{
scanf("%d",&a[i]),a[i]/=2;
}
long long ans = 0;
for(int i = 0; i < n/2; i++)
{
ans+=i-sum(a[i]),add(a[i],1);
}
priority_queue<int>pq;
for(int i = 0; i < n/2; i++)
{
pq.push(a[i]);
if(pq.top() > a[i])
{
ans += pq.top()-a[i];
pq.pop();
pq.push(a[i]);
}
}
cout << ans <<endl;
return 0;
}