题目的意思是,你有一行的盒子,這邪恶盒子是按照序号1-n的顺序进行排列的,现在你要做的就是,在给你一个n和一个m的时候,其中的n是指由多少个盒子在排列,m是指要执行多少次的操作,这里一共有4中操作,其中一是,输入1 1 2就是执行第一次操作,如果1实在2的左边这不用进行操作,如果1在2的右边那么就要把1放到2的左边,同样的2号的操作就是输入2 2 3,意思是进行2操作,如果2在3 的右边就不用进行操作,如果2在3的左边就要把2移动到3的右边,还有就是3号操作,直接将输入的两个数进行互相交换。至于4操作就是将这一列的数字首位倒置。
变动一个数子的话只会涉及到整个数字左右的两个数字,所以的话就要两个标记来进行变动。这里设置了两个数组来表示这两个标记。4种操作中的第四个可以不用进行任何的动作,只需要进行一次标记就可以完成第四个操作了,所以这里可以设置一个标记,每次进行操作的时候通过判断这个标记是否存在来进行操作,比如如果这个标记是存在的,那么进行第一个操作的时候就变成了进行第二个操作了,而第三个操作就可以不用进行了。同时书上的源程序有很多值得学习的地方,例如在输入标记的数组right的时候,使用的是right[i]=(i+1)%(n+1);这样的好处就是可以防止数据的输入越界。还有就是在写程序的时候要注意的是每一部分要规范的进行书写,让人感觉层次分明。还有很巧妙的一点就是在最后的时候当标记标记显示是执行过4号操作的时候,要计算相反的序号地和,书中是通过计算前n项的和减去计算出来的奇数项。
源代码:
#include<cstdio>
#include<cstring>
const int maxn=100000+10;
int n,left[maxn],right[maxn];
void link(int L,int R)
{
right[L]=R;
left[R]=L;
}
void swap(int &x,int &y)
{
int a;
a=x;
x=y;
y=a;
}
int main()
{
int m,kase=0;
while(scanf("%d%d",&n,&m)==2)
{
for(int i=1;i<=n;i++)
{
left[i]=i-1;
right[i]=(i+1)%(n+1);
}
right[0]=1;
left[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&&right[Y]==X) swap(X,Y);
if(op!=3&&inv)op=3-op;
if(op==1&&X==left[Y])continue;
if(op==2&&Y==right[X])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(Y,X);
link(X,RY);
}
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];
if(i%2==1)
ans+=b;
}
if(inv&&n%2==0)
ans=(long long)n*(n+1)/2-ans;
printf("Case %d: %lld\n",++kase,ans);
}
return 0;
}