bzoj 1106: [POI2007]立方体大作战tet(贪心+树状数组)
2017-11-18 19:00
330 查看
1106: [POI2007]立方体大作战tet
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 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
样例输入15
5 2 3 1 4 1 4 3 5 2
样例输入2
3
1 2 3 1 2 3
Sample Output
样例输出12
样例输出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 */
相关文章推荐
- BZOJ1106: [POI2007]立方体大作战tet
- BZOJ1106 [POI2007]立方体大作战tet
- [BZOJ 1106] [POI2007] 立方体大作战tet 【树状数组】
- BZOJ 1106 POI2007 立方体大作战tet 模拟
- 1106: [POI2007]立方体大作战tet 思路题 贪心
- bzoj1106 [POI2007]立方体大作战tet
- 【BZOJ 1106】 [POI2007]立方体大作战tet
- BZOJ 1106 POI2007 立方体大作战tet 模拟
- [bzoj1106][POI2007]立方体大作战tet
- [BZOJ1106] [POI2007]立方体大作战tet
- 【bzoj1106】 [POI2007]立方体大作战tet
- BZOJ 1106: [POI2007]立方体大作战tet
- bzoj1106: [POI2007]立方体大作战tet
- [bzoj1106] [POI2007]立方体大作战tet
- BZOJ1106: [POI2007]立方体大作战tet
- BZOJ1106 [POI2007]立方体大作战tet
- [BZOJ]1106: [POI2007]立方体大作战tet
- bzoj1106: [POI2007]立方体大作战tet
- 【POI2007】【BZOJ1106】立方体大作战tet
- BZOJ 1106 [POI2007]立方体大作战tet(树状数组)