题目链接:https://cn.vjudge.net/problem/UVA-12657
Boxes in a Line
You have n boxes in a line on the table numbered 1…n from left to right. Your task is to simulate 4 kinds of commands:
- 1 X Y : move box X to the left to Y (ignore this if X is already the left of Y)
- 2 X Y : move box X to the right to Y (ignore this if X is already the right of Y)
- 3 X Y : swap box X and Y
- 4 : reverse the whole line.
Commands are guaranteed to be valid, i.e. X will be not equal to Y.
For example, if n = 6, after executing 1 1 4, the line becomes 2 3 1 4 5 6. Then after executing 2 3 5, the line becomes 2 1 4 5 3 6. Then after executing 3 1 6, the line becomes 2 6 4 5 3 1. Then after executing 4, then line becomes 1 3 5 4 6 2
Input
There will be at most 10 test cases. Each test case begins with a line containing 2 integers n,m(1≤n,m≤100,000). Each of the following m lines contain a command.
Output
For each test case, print the sum of numbers at odd-indexed positions. Positions are numbered 1 to n from left to right.
Sample Input
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
Sample Output
Case 1: 12
Case 2: 9
Case 3: 2500050000
题意:你有一行盒子从左至右编号依次为1,2,3,4……,n。可以执行以下四种指令:
- 1 X Y 表示把盒子X移动到Y左边(如果X已经在Y的左边则忽略此指令)。
- 2 X Y 表示把盒子X移动到Y右边(如果X已经在Y的右边则忽略此指令)。
- 3 X Y 表示交换盒子X Y 的位置。
- 4 表示反转整条链。
执行完所有指令后输出奇数位上数字之和。
思路:用双向链表来记录每一个数字的左边和右边,从0开始,0的右边为编号为1的数,0的右边为编号为n的数。其中利用link函数来连接两个节点,并且,对于指令4,可以巧妙的采用标记的方法,而不是真的将整个链反转。若标记为真,则遇到指令1,2时,可用op=3-op 来转化。当遇到指令3时,还需考虑X Y 相邻的情况。
void link(int l,int r)
{
rightt[l]=r;
leftt[r]=l;
}
参考代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
using namespace std;
const int maxn=100005;
int rightt[maxn],leftt[maxn];
void link(int l,int r)
{
rightt[l]=r;
leftt[r]=l;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n,m,kase=0;
while(~scanf("%d%d",&n,&m))
{
for(int i=1; i<=n; i++) //初始化left和right数组
{
leftt[i]=i-1;
rightt[i]=(i+1)%(n+1);//r[n]=0;
}
rightt[0]=1;
leftt[0]=n;
int inv=0,x,y,op;
while(m--)
{
scanf("%d",&op);
if(op==4)
inv=!inv;
else
{
scanf("%d%d",&x,&y);
if(op==3&&leftt[x]==y)
{
int t=x;
x=y;
y=t;
}
if(op!=3&&inv)
op=3-op;
if(op==1&&x==leftt[y])
continue;
if(op==2&&x==rightt[y])
continue;
//此处另设变量来存储原始的ly,lx,ry,rx值。
int ly=leftt[y],lx=leftt[x],rx=rightt[x],ry=rightt[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(leftt[y]==x)
{
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 summ=0;
for(int i=1;i<=n;i++)
{
b=rightt[b];
if(i%2==1)
summ+=b;
}
if(inv&&n%2==0)
summ=(long long)n*(n+1)/2-summ;
printf("Case %d: %lld\n",++kase,summ);
}
return 0;
}