Description
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 nfrom left to right.
Sample Input
6 41 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: 12Case 2: 9
Case 3: 2500050000
这道题还是链表的应用,但是显然单向链表已经不行了,所以我们使用双向链表,同样我们不用指针来做,还是用数组——用right【i】和left【i】来表示i的左边和右边的数。执行前三条指令时,我们只需要修改数字之间的链接即可,下面这个函数可以起到这个作用:
void link(int L,int R)
{
right【L】=R;left【R】=L;
}
在双向链表这样复杂的结构中,常常编写辅助函数来设置链接关系。
第四个反转操作比较麻烦,这时候我们可以用加标记的方法来处理,并不用真的执行这个操作。我们只需标记下来反转了没,如果反转了,则1、2操作将会对换(即x放到y的左边就会变成放到y的右边,因为反转过后相对位置就会改变)。代码如下:
#include<cstdio>
using namespace std;
const int maxn=100000+5;
int main()
{
int n,com,count=0;
while(scanf("%d%d",&n,&com)==2)
{
int right[maxn],left[maxn];
for(int i=0;i<=n;i++) right[i]=i+1;
for(int i=n;i>0;i--) left[i]=i-1;
int vir=0;
for(int i=0;i<com;i++)
{
int m,x,y;
scanf("%d",&m);
if(m==4) vir=(!vir);
else
{
scanf("%d%d",&x,&y);
if(vir&&m!=3) m=3-m;
if(m==1&&right[x]==y) continue;
if(m==2&&right[y]==x) continue;
int lx=left[x],rx=right[x],ly=left[y],ry=right[y];
if(m==1)
{
right[lx]=rx;left[rx]=lx;
right[ly]=x;left[x]=ly;
right[x]=y;left[y]=x;
}
if(m==2)
{
right[lx]=rx;left[rx]=lx;
right[y]=x;left[x]=y;
right[x]=ry;left[ry]=x;
}
if(m==3)
{
if(right[x]==y)
{
right[lx]=y;left[y]=lx;
right[y]=x;left[x]=y;
left[ry]=x;right[x]=ry;
}
else if(right[y]==x)
{
right[ly]=x;left[x]=ly;
right[x]=y;left[y]=x;
left[rx]=y;right[y]=rx;
}
else
{
right[lx]=y;left[y]=lx;
left[rx]=y;right[y]=rx;
right[ly]=x;left[x]=ly;
left[ry]=x;right[x]=ry;
}
}
}
}
int b=0;
long long int ans=0;
for(int i=1;i<=n;i++)
{
b=right[b];
if(i%2!=0) ans+=b;
}
if(vir&&(n%2==0)) ans=(long long int)n*(n+1)/2-ans;
printf("Case %d: %lld\n",++count,ans);
}
return 0;
}
我犯了两个错误,导致代码迟迟不能通过:
1.long long的占位符写成了%d
2.
1. if(vir&&m!=3) m=3-m;
2. if(m==1&&right[x]==y) continue;
3. if(m==2&&right[y]==x) continue;
上面三条语句的顺序写成了2、3、1.细想一下,如果执行了反转操作,那么相对位置就会改变,那么如果输入的命令是把x放到y的左边,初始时为:x,y而执行了反转后为:y,x,此时当然可以执行把x放到左边,但是如果第一条语句在最后的时候,就会continue,当然是错的