洛谷3460 [POI2007]TET-Tetris Attack(贪心)(树状数组)

16 篇文章 0 订阅
14 篇文章 0 订阅

题意

给定一个长度为2n的序列,1~n各出现两次,可以交换相邻两项,两个同样的数放在一起会对消,求把所有数对消的最小交换次数,并输出方案。

特性

一种很显然的贪心,两两间原始距离最近的先合并,再到远的。这么做是为了在包含关系的时候先处理掉里面的。
如果要是交叉的话,先删哪个都没所谓,可以自己YY一下。

心路

所以我就想排序后用树状数组维护编号,其它模拟就好,因为总步数才1 000 000,用并查集跳过删除的数字。
结果又T又W(大部分还是对的),不知道为什么。

题解

贪心+树状数组
其实排序可以省掉,只要按顺序每到两个都出现的时候移动到它们消掉就可以了。因为按顺序的时候肯定先把区间小的先访问到,这样省了个O(N logN)的时间。
树状数组不变,还有,因为在把一个数字移到相对应的数字旁边时,很明显路径是连续的,所以可以用一个for来填写。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=50010,MAXC=1000010;//debug 看错 MAXC!=2*MAXN

int n,m,size=0,pos[MAXN];

int s[MAXN*2];
void add(int x,int c)
{
    for(;x<=m;x+=x&-x) s[x]+=c;
}
int getsum(int x)
{
    int re=0;
    for(;x>=1;x-=x&-x) re+=s[x];

    return re;
}

int tot=0,list[MAXC];
int main()
{
    scanf("%d",&n);m=2*n;
    for(int i=1;i<=m;i++)
    {
        int x;scanf("%d",&x);
        if(!pos[x]) pos[x]=i,add(i,1);
        else
        {
            add(pos[x],-1);int res=getsum(i)-getsum(pos[x]-1);//求出两点之间非空的位置有多少个
            for(int p=i-size-1;res;res--,p--) list[++tot]=p;//填写方案数组
            size+=2;
        }
    }
    
    printf("%d\n",tot);
    for(int i=1;i<=tot;i++) printf("%d\n",list[i]);
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值