P1966

[NOIP2013 提高组] 火柴排队

题目描述

涵涵有两盒火柴,每盒装有 \(n\) 根火柴,每根火柴都有一个高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为:$ \sum (a_i-b_i)^2$

其中 \(a_i\) 表示第一列火柴中第 \(i\) 个火柴的高度,\(b_i\) 表示第二列火柴中第 \(i\) 个火柴的高度。

每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 \(10^8-3\) 取模的结果。

输入格式

共三行,第一行包含一个整数 \(n\),表示每盒中火柴的数目。

第二行有 \(n\) 个整数,每两个整数之间用一个空格隔开,表示第一列火柴的高度。

第三行有 \(n\) 个整数,每两个整数之间用一个空格隔开,表示第二列火柴的高度。

输出格式

一个整数,表示最少交换次数对 \(10^8-3\) 取模的结果。

样例 #1

样例输入 #1

4
2 3 1 4
3 2 1 4

样例输出 #1

1

样例 #2

样例输入 #2

4
1 3 4 2
1 7 2 4

样例输出 #2

2

提示

【输入输出样例说明一】

最小距离是$ 0$,最少需要交换 \(1\) 次,比如:交换第 $1 \(列的前\) 2$ 根火柴或者交换第 \(2\) 列的前 $2 $根火柴。

【输入输出样例说明二】

最小距离是 \(10\),最少需要交换 \(2\) 次,比如:交换第 \(1\) 列的中间 \(2\) 根火柴的位置,再交换第 \(2\) 列中后 \(2\) 根火柴的位置。

【数据范围】

对于 \(10\%\) 的数据, \(1 \leq n \leq 10\)

对于 \(30\%\) 的数据,\(1 \leq n \leq 100\)

对于 \(60\%\) 的数据,\(1 \leq n \leq 10^3\)

对于 \(100\%\) 的数据,\(1 \leq n \leq 10^5\)\(0 \leq\) 火柴高度 \(< 2^{31}\)

超级好题!
首先可以直觉感觉出 肯定是最小的跟最小的 次小的跟次小的…(我发现了)
所以 首先离散化 (我也发现了)
可以感觉出答案跟逆序对有关 (我又发现了)
有个小结论:任意序列按题中交换方式回到1~n需要的次数就是逆序对数(我还是发现了)
最妙的一步(就差这步啊啊啊啊!):
构造一个映射 q[i]:a中的第i个在b中的位置!那么交换使得a=b
等价于将q排成1~n !!!!!!
所以答案就是q的逆序对数

随着难度的提高 练习的深入 要多掌握技巧方法 不要气馁 Forza!
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=100005;
const int mod=1e8-3;
int tr[maxn];
int n,a1[100005],b1[100005],c1[100005],a2[100005],b2[100005],c2[100005],p[maxn],q[maxn];
int lowbit(int x)
{
	return x&(-x);
}
void add(int p,int k)
{
	for(;p<=n;p+=lowbit(p))
		tr[p]+=k;
}
int query(int p)
{
	int sum=0;
	for(;p;p-=lowbit(p))
		sum+=tr[p];
	return sum; 
}
signed main()
{
	ios::sync_with_stdio(false);
	cin>>n;
	for(int i=1;i<=n;i++)cin>>b1[i],c1[i]=b1[i];
	for(int i=1;i<=n;i++)cin>>b2[i],c2[i]=b2[i];
	sort(c1+1,c1+n+1);
	for(int i=1;i<=n;i++)
	{
		int pos=lower_bound(c1+1,c1+n+1,b1[i])-c1;
		a1[i]=pos;
	}
	sort(c2+1,c2+n+1);
	for(int i=1;i<=n;i++)
	{
		int pos=lower_bound(c2+1,c2+n+1,b2[i])-c2;
		a2[i]=pos;
	}
	for(int i=1;i<=n;i++)
		p[a2[i]]=i;
	for(int i=1;i<=n;i++)
		q[i]=p[a1[i]];
//	for(int i=1;i<=n;i++)cout<<q[i]<<" ";cout<<"\n";
	int nxd=0;
	for(int i=1;i<=n;i++)
	{
		add(q[i],1);
		nxd+=i-query(q[i]);
		nxd%=mod;
	}
	cout<<nxd<<"\n";
	return 0;
}
posted @ 2023-01-06 22:50  PKU_IMCOMING  阅读(10)  评论(0)    收藏  举报