LOJ#2610. 「NOIP2013」货车运输

猜一波结论:把数组 \(a,b\) 排序,然后一个一个累加就是最优答案。这个结论很容易证明。

现在问题就转换成了:给你一个数组 \(b\),再给你一个数组 \(a\),问你最少将 \(a\) 中相邻的数交换多少次才能将 \(a,b\) 中每个数的排名一一对应。注意到交换相邻的两个数,相当于冒泡排序中消除逆序对的过程,所以根据 \(a\) 排序后的下标对 \(b\) 离散化,然后树状数组求逆序对即可。

时间复杂度 \(\mathcal O(n\log n)\)

#include<bits/stdc++.h>
using namespace std;
const int N=100000,MOD=99999997;
struct node
{
	int val,pos;
	bool operator < (const node &x) const {return val<x.val;}
}ta[N+10],tb[N+10];
int a[N+10],b[N+10];
int n,c[N+10];
int lowbit(int x) {return x&-x;}
void modify(int x,int d)
{
	while(x<=n)
	{
		c[x]+=d;
		x+=lowbit(x); 
	} 
}
int query(int x)
{
	int ans=0;
	while(x>0)
	{
		ans+=c[x];
		x-=lowbit(x);
	}
	return ans;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		ta[i].val=a[i];
		ta[i].pos=i; 
	}
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&b[i]);
		tb[i].val=b[i];
		tb[i].pos=i;
	}
	sort(ta+1,ta+n+1);
	sort(tb+1,tb+n+1);
//	for(int i=1;i<=n;i++) printf("%d ",ta[i].val);
//	puts("");
//	for(int i=1;i<=n;i++) printf("%d ",tb[i].val);
	for(int i=1;i<=n;i++) b[ta[i].pos]=tb[i].pos;
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		modify(b[i],1);
		ans=(ans+(query(n)-query(b[i])))%MOD;
	}
	printf("%d",ans);
	return 0;
}
posted @ 2020-10-07 21:58  zzt1208  阅读(88)  评论(1编辑  收藏  举报