P5749
[IOI2019]排列鞋子
题目描述
Adnan 拥有巴库最大的鞋店。现在有一个装着 \(n\) 双鞋的箱子刚运到他的鞋店。每双鞋是大小相同的两只:一只左脚,一只右脚。Adnan 把这 \(2n\) 只鞋排成一行,该行总共有 \(2n\) 个位置,从左到右编号为 \(0\) 到 \(2n-1\) 。
Adnan 想把这些鞋子重新排成合法的排列。一个排列是合法的,当且仅当对于所有的 \(i(0\leqslant i \leqslant n - 1)\),以下条件都成立:
- 在位置 \(2i\) 和 \(2i+1\) 上的鞋子大小相同;
 - 在位置 \(2i\) 上的鞋子是一只左脚鞋;
 - 在位置 \(2i+1\) 上的鞋子是一只右脚鞋。
 
为实现上述目标,Adnan 可以做一系列对调。在每次对调中,他选择当前相邻的两只鞋进行对调(也就是把它们拿起来,然后将每只鞋子放回到另一只鞋子原来的位置上)。两只鞋子是相邻的,当且仅当其位置编号的差为 \(1\)。
请求出 Adnan 最少要做出多少次对调,才能得到一个合法排列。
输入格式
第一行一个正整数 \(n\),表示有 \(n\) 双鞋。
第二行 \(2n\) 个整数 \(S_i\),第 \(i\) 个整数表示位置编号为 \(i-1\) 的鞋子。其中 \(|S_u|\neq 0\),等于最初在位置 \(i\) 上的鞋子的大小。这里 \(|x|\) 表示 \(x\) 的绝对值,当 \(x\geq 0\) 时等于 \(x\),当 \(x < 0\) 时等于 \(-x\)。如果 \(S_i < 0\),则 \(i\) 位置上的鞋子是一只左脚鞋,否则是右脚鞋。
输出格式
输出一行一个整数,表示最少对调次数。
样例 #1
样例输入 #1
2
2 1 -1 -2
样例输出 #1
4
样例 #2
样例输入 #2
3
-2 2 2 -2 -2 2
样例输出 #2
1
提示
样例说明 1
Adnan 可以通过 \(4\) 次对调而得到一个合法的排列。
例如,他可以先对调 \(1\) 和 \(-1\),再对调 \(1\) 和 \(-2\),再对调 \(-1\) 和 \(-2\)。最后对调 \(-2\) 和 \(2\)。随后他就可以得到合法的排列 。无法用少于 \(4\) 次对调就得到合法的排列,因此输出 \(4\)。

样例说明 2
Adnan 可以对调在位置 \(2\) 和 \(3\) 上的鞋子来得到合法的排列\([-2,2,-2,2,-2,2]\),因此应当输出 \(1\)。
数据范围
对于所有数据:
- \(1\leqslant n\leqslant10^5\);
 - 对于所有\(i(0\leqslant i\leqslant 2n-1)\),都有\(1\leqslant \left|S_{i+1}\right|\leqslant n\);
 - 总有某个合法的排列可以经由一系列对调而得到。
 
详细子任务附加限制与分值如下表:
| 子任务编号 | 附加限制 | 分值 | 
|---|---|---|
| \(1\) | \(n=1\) | \(10\) | 
| \(2\) | \(n\leqslant8\) | \(20\) | 
| \(3\) | 所有鞋子大小都是相同的 | \(20\) | 
| \(4\) | 所有在位置 \(0,\dots,n-1\) 上的鞋都是左脚鞋,而在位置 \(n,\dots,2n-1\) 上的鞋都是右脚鞋。而且对于所有 \(i(0\leqslant i\leqslant n-1)\),在位置 \(i\) 和 \(i+n\) 上的鞋子大小相同 | \(15\) | 
| \(5\) | \(n\leqslant10^3\) | \(20\) | 
| \(6\) | 无附加限制 | \(15\) | 
好题!
首先有个很重要的点!
交换相邻的达到目标状态的最小次数=1~n 到目标状态排列的逆序对数
跟火柴排队类似!
所以我们只要求出最后哪些鞋子是要相邻配对的数组即可
很容易想到从前到后依次扫 遇到一个-x就找到最近的且未配对的+x与它配对 代码实现可以用队列+vis[]一定要手写队列! 也可以先正着扫存每个鞋子大小的位置 vector 然后反着扫每次遇到+x就将vector最后一个取出来配对 然后pop_back()即可
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int tr[100005*4];
int n,a[200005];
int lowbit(int x)
{
	return x&(-x);
}
void add(int p,int x)
{
	for(;p<=n;p+=lowbit(p))
		tr[p]+=x;
}
int query(int p)
{
	int sum=0;
	for(;p;p-=lowbit(p))
		sum+=tr[p];
	return sum;
}
vector<int>match[200005]; 
struct did{
	int l,r;
}b[200005];
int d[200005];
bool cmp(did x,did y)
{
	return min(x.l,x.r)<min(y.l,y.r);
}
signed main()
{
	ios::sync_with_stdio(false);
	cin>>n;
	n*=2;
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1;i<=n;i++)
		if(a[i]<0)match[-a[i]].push_back(i);
	int m=0;
	for(int i=n;i>=1;i--)
		if(a[i]>0)
		{
			b[++m].l=match[a[i]][match[a[i]].size()-1];
			match[a[i]].pop_back();
			b[m].r=i;
		}
	sort(b+1,b+n/2+1,cmp);
	int tot=0;
	for(int i=1;i<=n/2;i++)
	{
		d[i*2-1]=b[i].l;
		d[i*2]=b[i].r;
	}
	for(int i=1;i<=n;i++)
	{
		add(d[i],1);
		tot+=i-query(d[i]);
	}
	cout<<tot<<"\n";
	return 0;
}
                    
                
                
            
        
浙公网安备 33010602011771号