第八周

6—5•你有一行盒子,从左到右依次号为1,2,3……,n可以执行以下4种指

p1 X Y表示把盒子X移动到盒子Y的左边(如果X已经在Y的左边则忽略此指令)

p2 X Y表示把盒子X移动到盒子Y的右边(如果X已经在Y的右边则忽略此指令)

p3 X Y表示交换盒子X和Y的位置

p4表示反转整条链

    指令保证合法,即X不等于Y。例如:当n=6时在初始状态下执行1 1 4后,盒子序列为2 3 1 4 5 6。接下来执行2 3 5,盒子序列变成2 1 4 5 3 6.再执行3 1 6,得到2 6 4 5 3 1,最终执行4,得到1 3 5 4 6 2


•输入包含不超过10组数据,每行数据第一行为盒子个数n和指令条数m(1<=n,m<=100000),以下m行每行包含一条指令。每组数据输出一行,即所有技术位置的盒子编号之和。位置从左到右编号为1~n。

样例输入

6 4

1 1 4

2 3 5

3 1 6

4

6 3

1 1 4

2 3 5

3 1 6

100000 1

4

样例输出:

Case 1:12

Case 2:9

Case 3:2500050000

思路:该题用到了双向链表的思想,即
right[L] = R ; left[R] = L;
①在四个步骤中,4是复杂的,需要用到翻转,如果直接翻转会很耗时,所以采用标记的方法,用inv来标记,执行了几次步骤4,当执行步骤四后,执行步骤一想就是执行步骤二,执行步骤二就是执行步骤一,用下图来解释:

当执行一次步骤4时,inv=1,这个时候这个序列在程序中并没有变,变得只是步骤1.2的替换

②现在来解释步骤1和步骤2,link函数可以直接看为是将里面的参数按顺序排放,如link(x,z)就是把x放在z 的左边,在执行步骤1时要先判断x不在y的左边才要实行,然后执行link(LX, RX), link(LY,X), link(X,Y)

步骤2.3也是用一样的方法

代码为:

#include <iostream>

#include <cstdio>

using namespace std;

const int maxn=100000+5;

int n,leftt[maxn],rightt[maxn];//left and right is ambiguous

void link(int L,int R)

{

    rightt[L]=R;leftt[R]=L;

}

int main()

{

    int m,kase=0;

    while(scanf("%d%d",&n,&m)==2)

{

        for(int i=1;i<=n;i++)

{

            leftt[i]=i-1;

            rightt[i]=(i+1)%(n+1);

        }

        rightt[0]=1;leftt[0]=n;

        int op,X,Y,inv=0;

        while(m--)

{

            scanf("%d",&op);

            if(op==4) inv=!inv;

            else{

                scanf("%d%d",&X,&Y);

                if(op==3&&rightt[Y]==X) swap(X,Y);//!为了转化为同一种情况来处理,x、y只是一个代号,反正结果变得是值

                if(op!=3&&inv) op=3-op;

                if(op==1&&X==leftt[Y]) continue;

                if(op==2&&X==rightt[Y]) continue;

                int LX=leftt[X],RX=rightt[X],LY=leftt[Y],RY=rightt[Y];

                //下面分类讨论,不要漏掉

                if(op==1){

                    link(LX,RX);link(LY,X);link(X,Y);

                }//X的左右连起来,X和Y左,X和Y

                else if(op==2){

                    link(LX,RX);link(Y,X);link(X,RY);

                }//X的左右连起来,Y和X,X和Y右    按照链的顺序来写,可能思路更清晰

                else if(op==3){

                    if(rightt[X]==Y) {link(LX,Y);link(Y,X);link(X,RY);}

                    else {link(LX,Y);link(Y,RX);link(LY,X);link(X,RY);}

                }

            }

        }

        int b=0;

        long long ans=0;

        for(int i=1;i<=n;i++)

{

            b=rightt[b];//向右推移

            if(i%2==1) ans+=b;

        }

        if(inv&&n%2==0) ans=(long long)n*(n+1)/2-ans;//如果n不是偶数的话,倒一下结果也一样

        printf("Case %d:  %lld\n",++kase,ans);

    }

    return 0;

}

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一、简述systemd的新特性及unit常见类型分析,能够实现编译安装的如nginx\apache实现通过syst...
    N32_Diamond阅读 1,462评论 2 4
  • 1、用shell脚本实现自动登录机器 2、shell 判断一个值bone是否在数组arrayZ=( one two...
    ritch阅读 161评论 0 0
  • day7 一、junit的使用 单元测试测试对象 是一个类中的方法单元测试方法时候,方法命名规则public...
    mwj610阅读 329评论 0 0
  • 搜索内核代码中schedule函数的位置 以上仅是schedule()所在的部分位置,但通过其所在模块可以看出,它...
    Sawoom阅读 629评论 0 0
  • 给我吃个虾条吧?你吃够了。我没吃够。你看你肚肚都撑大了!两岁四个月的对话,我竟无言以对。哈哈哈
    我一个人跳舞55阅读 177评论 0 0