您的位置:首页 > 其它

bzoj 1106: [POI2007]立方体大作战tet(贪心+树状数组)

2017-11-18 19:00 330 查看

1106: [POI2007]立方体大作战tet

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 785  Solved: 574

[Submit][Status][Discuss]


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

样例输入2

3

1 2 3 1 2 3

Sample Output

样例输出1

2

样例输出2

3

知道思路这题是非常好写的

思路:

贪心,遍历每个数,如果这个数字已经出现过了,答案加上这两个数之间其它数字的个数

并将这个数字从数列中删去就行了

例如:

1 2 3 2 3 1

当遍历到第4个数'2'时,中间有个3,ans++

当遍历到第5个数'3'时,中间没有数字(有个2但已经被删了)

当遍历到第6个数'1'时,中间也没有数字(2和3都被删了)

所以最后答案是1

上面的步骤同时也是证明:删除任意一对数时,一定要保证中间已经没有相同的数字了才是最优解

过程可以用树状数组维护

#include<stdio.h>
#define LL long long
int n, flag[50005], tre[100005];
void Update(int k, int x)
{
while(k<=n*2)
{
tre[k] += x;
k += k&-k;
}
}
int Query(int k)
{
int ans = 0;
while(k)
{
ans += tre[k];
k -= k&-k;
}
return ans;
}
int main(void)
{
LL ans;
int i, x;
scanf("%d", &n);
ans = 0;
for(i=1;i<=2*n;i++)
{
scanf("%d", &x);
if(flag[x]==0)
{
Update(i, 1);
flag[x] = i;
}
else
{
ans += Query(i)-Query(flag[x]);
Update(flag[x], -1);
}
}
printf("%lld\n", ans);
return 0;
}
/*
3
1 2 3 2 3 1
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: