题目链接:https://vjudge.net/problem/UVA-12657
题目大意:输入n,m 代表有n个盒子 每个盒子最开始按1~n排成一行 m个操作,
1 x y :把盒子x放到y的左边
2 x y: 把盒子x放到y 的右边
3 x y:调换x y盒子的位置
4 表示反转整条链
思路:也是很明显的暴力 模拟 。 但是值得提的是 虽然是暴力,但是却是用的双向链表来暴力。
有很多要注意的地方 :
当操作4的时候,我们可以把本次操作记录一下,不必直接把全部的位置反转 试想一下,如果每次出现一个4 每次都反转 那多麻烦 (我们要反转的话,首先得找到最后一个盒子,然后从最后一个盒子往前重新存储一遍)
但是如果有记录操作4注意再碰到其他操作 也要随之改变 :
当有记录4的时候 操作1就相当于操作2 操作2相当于操作1
还有注意的是 操作3 两个盒子交换位置 : 两个盒子相邻和不相邻是不一样的 切记!!!
最后 要输出结果的话 : 注意有没有操作4 如果有操作4的话 如果是奇数 反转一次对结果没有影响 但是偶数 的话 反转一次 我们现在求的刚好的偶数位的 总的减掉就是答案了
具体看代码:
#include<iostream> #include<string.h> #include<vector> #include<stdio.h> using namespace std; const int maxn=1e5+5; int n; int Left[maxn]; int Right[maxn]; void link(int l,int r) //两个节点相连 { Right[l]=r; Left[r]=l; } int main() { int m,ca=0; while(scanf("%d%d",&n,&m)!=EOF) { for(int i=1;i<=n;i++)//存好节点 { Left[i]=i-1; Right[i]=(i+1)%(n+1);//这里为何%(n+1) 试想一下 最后一个元素的右端是谁 显然是第一个元素0 } Left[0]=n; Right[0]=1; 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&&Right[y]==x) swap(x,y);// if(op!=3&&inv) op=3-op;//当调整一次顺序的时候 操作1和2 刚好相反 可以自己举例子 if(op==1&&x==Left[y]) continue;//已经满足条件了 if(op==2&&x==Right[y]) continue; int lx=Left[x],rx=Right[x],ly=Left[y],ry=Right[y]; if(op==1) //调整位置 { link(lx,rx); link(ly,x); link(x,y); } else if(op==2) { link(lx,rx); link(x,ry); link(y,x); } else if(op==3)//注意两者相连和不相连交换位置操作是不一样的 !!! { if(Right[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=Right[b];//其实b就是i位置对应的值 可以仔细想一下 if(i%2==1) ans+=b; } if(inv&&n%2==0) ans=(long long)n*(n+1)/2-ans;//自己举个例子就可以明白 n为奇数没有影响 printf("Case %d: %lld ",++ca,ans); } return 0; }