【洛谷P1966】[NOIP2013 提高组] 火柴排队

题解

逆序对板子,关键在于“把序列 \(a_i\) 根据 \(b_i\) 排序”的操作。
相当于把 \(a_i\) 序列对应成 \(1,2,3,4,5...\)
\(b_i\) 序列按照相同的对应法则对应成新的序列,这样这个序列就相当于要排列回 \(1,2,3,4,5...\),于是就是求逆序对了。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int INF = 0x3f3f3f3f,N = 1e5+10,mod = 1e8-3;
inline ll read()
{
	ll ret=0;char ch=' ',c=getchar();
	while(!(c>='0'&&c<='9')) ch=c,c=getchar();
	while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
	return ch=='-'?-ret:ret;
}
int n;
struct BIT
{
	int c[N];
	inline void update(int x,int v)
	{
		for(int i=x;i<=n;i+=i&-i)
			c[i]+=v;	
	}
	inline int query(int x)
	{
		int ret=0;
		for(int i=x;i;i-=i&-i) ret+=c[i];
		return ret;
	}
}tr;
int a[N],b[N];
int c[N],d[N],tot1,tot2;
int p[N];
void discrete()
{
	sort(c+1,c+n+1),sort(d+1,d+n+1);
	tot1=unique(c+1,c+n+1)-c-1;
	tot2=unique(d+1,d+n+1)-d-1;
	for(int i=1;i<=n;i++)
	{
		a[i]=lower_bound(c+1,c+tot1+1,a[i])-c;
		b[i]=lower_bound(d+1,d+tot2+1,b[i])-d;
	}
}
int cnt[N];
vector<int> mp[N];
void work()
{
	//for(int i=1;i<=n;i++) p[b[i]]=a[i];//p[a[i]]=b[i]    
	for(int i=1;i<=n;i++)
	{
		mp[a[i]].push_back(i);
		cnt[a[i]]++;
	}
	memset(cnt,0,sizeof(cnt));
	for(int i=1;i<=n;i++) p[i]=mp[b[i]][cnt[b[i]]++];
	/*相当于把b[i]根据a[i]排序,原本这个数在a[i]中的位置
	相当于把 a[i] 序列对应成 1,2,3,4,5 
	把b[i]序列按照相同的对应法则对应成新的序列 */ 
	ll ans=0;
	for(int i=1;i<=n;i++)	
	{
		tr.update(p[i],1);
		ans+=tr.query(n)-tr.query(p[i]);
		ans%=mod;
	}
	printf("%lld\n",ans);	
}
int main()
{
	n=read();
	for(int i=1;i<=n;i++) a[i]=c[i]=read();
	for(int i=1;i<=n;i++) b[i]=d[i]=read();
	discrete();
	work();
	return 0;
}
posted @ 2021-11-04 20:24  conprour  阅读(28)  评论(0编辑  收藏  举报