UVA 12657 Boxes in a Line

题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4395




题目意思是说,给出一个数n,表示存在一个整数序列1……n,然后进行四种操作:

操作一:输入x,y,表示将x移到y的左边(若x本来就在y的左边则忽略);

操作二:输入x,y,表示将x移到y的右边(若x本来就在y的右边则忽略);

操作三:输入x,y,表示交换x和y。

操作四:将整个序列倒置。

最后要求的是操作后的整个序列奇数项的和。

数据为100000,直接模拟肯定超时,用STL的链表也会超,我的想法是用数组模拟链表,left[i]和right[i]数组分别存放i的左值和右值。在整个过程中,逆序操作最耗时间,由于题目只需要求奇数项的和,在进行逆序操作时,我们没必要真真进行操作,只需要记录逆序的次数即可,若是奇数次,则最后求整个序列的偶数项之和,偶数次就是求奇数项之和。还有一点就是,操作四的进行与否会对前两种操作有一点影响,需要稍作处理。详细过程见代码:


//#include <algorithm>
//#include <iostream>       //这里不能用iostream,和right,left冲突,
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <vector>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
typedef long long LL;
const int maxn= 100000 + 10;

int left[maxn],right[maxn];
void link(int L, int R) {       //连接L和R,L在左边
    right[L] = R;
    left[R] = L;
}
int main() {
    int n,m,cas=1;
    while(~scanf("%d%d",&n,&m)) {
        for(int i=0; i<=n; i++) {
            link(i,i+1);
        }
        left[0]=n;
        right[n]=0;
        int op,flag=0,x,y;
        while(m--) {
            scanf("%d",&op);
            if(op==4) {         //判断是否进行逆序操作
                flag=!flag;
                continue;           //注意:当op==4时,不需要输入x,y.(这里找错找了好久……%>_<%……)
            }
            scanf("%d%d",&x,&y);
            if(op==3 && right[y]==x)    swap(x,y);  //方便后面判断交换是否相邻
            if(op!=3 && flag) op=3-op;          //进行逆序操作后,原来的左边变成右边,右边变成左边
            if(op==1 && left[y]==x) continue;
            if(op==2 && right[y]==x) continue;
            int lx=left[x],rx=right[x],ly=left[y],ry=right[y];
            if(op==1) {                 //将x移到y的左边
                link(lx,rx);
                link(ly,x);
                link(x,y);
            } else if(op==2) {          //将x移到y的右边
                link(lx,rx);
                link(y,x);
                link(x,ry);
            } else if(op==3) {          //交换x和y
                if(right[x]==y) {       //当x和y相邻时
                    link(lx,y);
                    link(y,x);
                    link(x,ry);
                } else {                //当x和y不相邻时
                    link(lx,y);
                    link(y,rx);
                    link(ly,x);
                    link(x,ry);
                }
            }
        }
        LL sum=0;
        int b=0;
        for(int i=1; i<=n; i++) {
            b=right[b];
            if(i%2) sum+=b;
        }
        if(flag && n%2==0) sum=(LL)n*(n+1)/2-sum;
        //如果逆序操作次数为奇数,则最终结果求的是整个序列的偶数项之和,此处是用 序列总和减去奇数项之和
        printf("Case %d: %lld\n",cas++,sum);
        //此处输出太坑了,由于cb只支持__int64,不支持%lld,而hustoj支持longlong不支持int64,WA了几次
    }
    return 0;
}


测试数据:

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



可惜这题在比赛时思路是对的,由于各种问题考虑不全没有做出来……还好只是普通的练习赛。。。


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值