火柴排隊
顯然我們要讓a中第i小的對應b中第i小的,粗略想一下,如果一個是2,3,一個是3,4。那麼2,3對應3,4比2,3對應4,3來的更好,因爲題目中的高度不同,而我們的例子是差最小的極端例子,所以可以得出結論成立。
那麼問題來了,怎麼一一對應。
先把a,b離散化(打上序號排序),然後根據a序號的順序排b的序號,此時b的序號,設爲數組c,c[i]表示b中c[i]位應該在第i位上,那麼只要求c的逆序對即可。
#include<bits/stdc++.h>
#define rep(i,k,n) for(int i=k;i<=n;i++)
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
using namespace std;
const int maxn=500005;
const ll modn=99999997;
pii a[maxn],in[3][maxn];
int n;
ll ans;
ll c[maxn];
inline int lowbit(int k)
{
return (k&(-k));
}
void add(int i)
{
while(i<=n)
{
c[i]++;
c[i]=c[i];
i+=lowbit(i);
}
}
ll getsum(int i)
{
ll sum=0;
while(i>0)
{
sum+=c[i];
sum=sum;
i-=lowbit(i);
}
return sum;
}
bool cmp(pii a,pii b)
{
return a.se<b.se;
}
int main()
{
// freopen("testdata (2).in","r",stdin);
scanf("%d",&n);
rep(i,1,n) scanf("%d",&in[1][i].fi),in[1][i].se=i;
rep(i,1,n) scanf("%d",&in[2][i].fi),in[2][i].se=i;
ll ans=0;
sort(in[1]+1,in[1]+n+1);sort(in[2]+1,in[2]+n+1);
rep(i,1,n)
{
a[in[1][i].se].fi=in[2][i].se;
a[i].se=i;
}
sort(a+1,a+n+1);
rep(i,1,n)
{
add(a[i].se);
ans+=i-getsum(a[i].se);
}
printf("%lld",ans%modn);
return 0;
}
前置知識:逆序對
只會樹狀數組求逆序對,想法很簡單,將數組離散化之後,從小到大做一個pair帶着原來的位置排序,然後再從小到大把數組插回原來的位置,統計已經有多少個數字在他前面查過了,那麼剩餘沒插的就是對於這個數的逆序數量,求和即可。
#include<bits/stdc++.h>
#define rep(i,k,n) for(int i=k;i<=n;i++)
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
using namespace std;
const int maxn=500005;
pii a[maxn];
int n;
ll ans;
ll c[maxn];
inline int lowbit(int k)
{
return (k&(-k));
}
void add(int i)
{
while(i<=n)
{
c[i]++;
i+=lowbit(i);
}
}
ll getsum(int i)
{
ll sum=0;
while(i>0)
{
sum+=c[i];
i-=lowbit(i);
}
return sum;
}
int main()
{
scanf("%d",&n);
rep(i,1,n)
{
scanf("%d",&a[i].fi);
a[i].se=i;
}
sort(a+1,a+n+1);
rep(i,1,n)
{
add(a[i].se);
ans+=i-getsum(a[i].se);
}
printf("%lld",ans);
return 0;
}