火柴排队
显然我们要让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;
}