例题6-5 UVA 12657 Boxes in a Line 移动盒子

感觉很好的一道题目。

看了很久:用到了双向链表。

1。用了两个数组left[maxn],right[maxn]代表当前元素的左边一个或者右边一个,当这个值为0的时候代表不存在!

2。对于4号命令,逆转整个序列,并没有真正的逆转,而是用inv 记录 是否逆转,利用了逆转两次等于没有逆转这个道理。逆转只会影响到1命令和2命令,3命令是XY换一下,并不会影响到,所以对与1和2,直接op = 3 - op即可!利用inv这个变量也有利于最后的输出,最后输出发现inv是0的话,就是没逆转,那么直接把奇数位置的数加起来即可,反之,要用总和减去这个偶数序列,(因为当n是偶数并且逆转的情况,sum其实是偶数位置!)

3。最后注意的一点,对于3号命令,是XY置换,XY相邻和XY相隔很多元素,处理是不一样的。


代码如下:


#include<iostream>
#include<cstdio>
const int maxn = 100000 + 10;
typedef long long ll;
int right[maxn],left[maxn];
void link(int x,int y){
    right[x]=y; left[y]=x;
}
int main()
{
    int n,m,cnt=0;
    while(scanf("%d%d",&n,&m) == 2){
        for (int i = 0; i <= n; ++i){
            left[i]=i-1;
            right[i]=(i+1)%(n+1);
        }
        left[0]=n; right[n]=0;
        int op,inv=0,X,Y;
        while(m--){
            scanf("%d",&op);
            if (op == 4)inv = !inv;
            else{
                scanf("%d%d",&X,&Y);
                if (inv && op != 3)op = 3 - op;
                if (op == 1 && right[X] == Y)continue;
                if (op == 2 && right[Y] == X)continue;
                int LX=left[X],RX=right[X],RY=right[Y],LY=left[Y];
                if (op == 1){link(LX,RX);link(LY,X);link(X,Y);}
                if (op == 2){link(LX,RX);link(Y,X);link(X,RY);}
                if (op == 3){
                    if (right[X] == Y){link(LX,Y);link(Y,X);link(X,RY);}
                    else if (right[Y] == X){link(LY,X);link(X,Y);link(Y,RX);}
                    else {link(LX,Y);link(Y,RX);link(LY,X);link(X,RY);}
                }
            }
        }
        ll ans=0;
        int b = 0;
        for (int i = 1; i <= n; ++i){
            b = right[b];
            if (i % 2 == 1)ans+=b;
        }
        if (n % 2 == 0 && inv)ans = (ll)(n+1)*n/2-ans;
        printf("Case %d: %lld\n",++cnt,ans);
    }
    return 0;
}


你可能感兴趣的:(链表,C语言,uva)