Test 3.27 T1 立方体大作战

Description

​ 一个叫做立方体大作战的游戏风靡整个 Byteotia。这个游戏的规则是相当复杂的,所以我们只介绍他的简单规则:给定玩家一个有 2n 个元素的栈,元素一个叠一个地放置。这些元素拥有 n 个不同的编号,每个编号正好有两个元素。玩家每次可以交换两个相邻的元素。如果在交换之后,两个相邻的元素编号相同.则将他们都从栈中移除,所有在他们上面的元素都会掉落下来并且可以导致连锁反应。玩家的目标是用最少的步数将方块全部消除。

Input

输入文件第一行包含一个正整数 n(1<=n<=50000)。接下来 2n 行每行一个数ai,从上到下描述整个栈,保证每个数出现且仅只出现两次(1<=ai<=n)。初始时,没有两个相同元素相邻。并且保证所有数据都能在 1000000 步以内出解。

Output

输出文件第一行包含一个数 m,表示最少的步数。

Sample Input #1

5

5

2

3

1

4

1

4

3

5

2

Sample Output #1

2

Sample Input #2

3

1

2

3

1

2

3

Sample Output

3

Solution

假设要消去第i个和第j个方块,那么当这两个方块消去时,只会影响有一个元素在区(i,j)中的两个元素的距离。那么我们需要以一种方式去消去这些方块。在决定两种方块的消去顺序时,假设其对应区间为包含关系,那么显然先消去被包含的区间要更优。若两个区间仅存在交集,那么无论先消去哪两个都一样。如果两个区间的交集为空,那么消去顺序对答案没有影响。综上所述,我们得到如下贪心策略:每当遇到一个重复出现的元素时就消去它。每次消去的操作次数即为区间中还没有消去的元素个数,可以转化为区间和用树状数组维护。如果一个点上有元素就设为1,消去后变为0。

#include <iostream>
#include <cstdio>
#define N 50002
using namespace std;
int n,i,pos[N],c[N],ans;
int lowbit(int x)
{
	return x&(-x);
}
void modify(int x,int y)
{
	for(int i=x;i<=2*n;i+=lowbit(i)) c[i]+=y;
}
int sum(int x)
{
	int ans=0;
	for(int i=x;i>=1;i-=lowbit(i)) ans+=c[i];
	return ans;
}
int main()
{
	freopen("tet.in","r",stdin);
	freopen("tet.out","w",stdout);
	cin>>n;
	for(i=1;i<=2*n;i++){
		int x;
		cin>>x;
		if(pos[x]==0){
			pos[x]=i;
			modify(i,1);
		}
		else{
			ans+=sum(i)-sum(pos[x]);
			modify(pos[x],-1);
		}
	}
	cout<<ans<<endl;
	fclose(stdin);
	fclose(stdout);
	return 0;
}

原文地址:https://www.cnblogs.com/LSlzf/p/10632380.html