• [洛谷P3460] [POI2007]TET-Tetris Attack


    洛谷题目链接:[POI2007]TET-Tetris Attack

    题目描述

    A puzzle called "Tetris Attack" has lately become a very popular game in Byteotia. The game itself is highlysophisticated, so we shall only introduce its simplified rules: the player is given a stack of (2n) elements, placedone on another and marked with (n) different symbols. Exactly two elements of the stack are marked with eachsymbol. A player's move consists in swapping two neighbouring elements, ie. interchanging them. If, as aresult of the swap, there are some two neighbouring elements marked with the same symbol, they are bothremoved from the stack. Then all the elements that have been above them fall down in consequence and mayvery well cause another removals. The player's goal is emptying the stack in the least possible number ofmoves.

    TaskWrite a programme that:

    reads the description of the initial stack content from the standard input, finds a solution with the minimum number of moves possible, writes out the outcome to the standard output.

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

    温馨提示,输出方案。

    输入输出格式

    输入格式:

    In the first line of the standard input there is one integer (n), (1le nle 50 000).

    The following (2n) lines describe theinitial content of the stack. The ((i+1))'th line contains one integer (a_i) -the symbol which the (i)'th ((1le a_ile n))element from the bottom is marked with. Each symbol appears in the stack exactly twice. Moreover, notwo identical symbols neighbour initially. The test data is well chosen so that a solution with no more than (1 000 000) moves exists.

    输出格式:

    A solution with the minimum number of moves possible should be written out to the standard output asfollows. The first line should contain one integer (m) -the minimum number of moves. The following (m) should describe the optimal solution itself, i.e. a sequence of (m) integers (p_1,cdots,p_m)​), one in each line. (p_i) denotes that in (i)'th move the player has chosen to swap the (p_i)'th and ((p_i+1))'th elements from the bottom.

    If more than one optimal solution exists, your programme should write out any one of them.

    输入输出样例

    输入样例#1:

    5
    5
    2
    3
    1
    4
    1
    4
    3
    5
    2

    输出样例#1:

    2
    5
    2

    说明

    SPJ返回WA:Something Left为方案错误

    温馨提示,输出方案。


    一句话题意: 给定一个长度为(2n)的序列,(1)~(n)各出现两次,可以交换相邻两项,两个同样的数放在一起会对消,求把所有数对消的最小交换次数.

    题解: 先直接讲做法吧:

    直接从(1)(2n)读入每个值,当这个值第一次出现就向树状数组这个位置+1,并记录下这个值第一次出现的位置. 当这个值第二次出现的时候计算这个值与它上一次出现的位置之间加入进的值,并把上一次修改的位置-1.

    那么这个方法为什么是正确的呢? (其实我自己做这道题的时候也是大力猜的结论233)

    我们可以简单证明一下(可能有点伪证的成分,感性理解一下):

    如果我们要使两个相同的数字合并,那么这两个数字中间的数字一定要合并.
    所以这样在我们第二遍扫到一个数字的时候,要合并这个数字,就至少要将这个数字之间的数字都合并掉.
    然而在树状数组中这个区间内只会有只出现过一次的数字,因为如果有还没计算的数字,就会在前面的循环中扫到.
    这样的话为了让这个数字能合并,至少需要让它与之前每一个数字交换一次,不然一定会有数字夹在这两个数字中间导致不能消掉这个数字.
    所以这样算出来的答案是可以保证最优的

    然后在输出方案的时候就每次算出距离就可以了,可以自己想一下怎么模拟算位置.

    #include<bits/stdc++.h>
    using namespace std;
    const int N=50000+5;
    
    int n, c[N*2], ans = 0, pos[N], stk[N*100], top = 0, res, size = 0, p;
    
    int lowbit(int x){ return -x & x; }
    void update(int x,int val){ for(;x<=n*2;x+=lowbit(x)) c[x] += val; }
    
    int query(int x){
        int res;
        for(res = 0;x;x-=lowbit(x)) res += c[x];
        return res;
    }
    
    int main(){
        int x; scanf("%d", &n);
        for(int i=1;i<=n*2;i++){
    	scanf("%d", &x);
    	if(pos[x]){
    	    update(pos[x], -1), res = query(i)-query(pos[x]-1);
    	    ans += res, p = i;
    	    while(res > 0) stk[++top] = p-size-1, p--, res--;
    	    size += 2;
    	}
    	else pos[x] = i, update(i, 1);
        }
        printf("%d
    ", ans);
        for(int i=1;i<=top;i++) printf("%d
    ", stk[i]);
        return 0;
    }
    
  • 相关阅读:
    STL常用容器☞String容器
    初识STL
    函数模板
    多态
    运算符重载
    友元
    对象的初始化和清理
    C++内存分区模型
    传值和传地址
    const的使用
  • 原文地址:https://www.cnblogs.com/BCOI/p/9594031.html
Copyright © 2020-2023  润新知