UVa 12657 - Boxes in a Line ( 双向链表 )
题意
你有一行盒子,从左到右依次编号为1, 2, 3,…, n。可以执行以下4种指令:
1 X Y表示把盒子X移动到盒子Y左边(如果X已经在Y的左边则忽略此指令)。
2 X Y表示把盒子X移动到盒子Y右边(如果X已经在Y的右边则忽略此指令)。
3 X Y表示交换盒子X和Y的位置。
4 表示反转整条链。
思路
双向链表
每次操作只需修改链表中的元素指向
另外, 如果程序一直在反转整条链, 如果一直操作的话必然复杂度很高
因为题目只求所有奇数位置标号之和, 当boxnum为奇数, 盒子逆序无影响
boxnum为偶数时才有影响, 再具体判断即可 . 所以将反转链操作用bool标记即可
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ULL;
const int maxn = 100000 + 10;
int l[maxn],r[maxn];
void link( int left, int right ){
r[left] = right;
l[right] = left;
}
int main()
{
int boxnum, casenum, i;
int x, a, b, num = 0;
ULL result;
bool ok;
while( ~scanf("%d%d",&boxnum, &casenum) ){
for( i = 1; i <= boxnum; i++ ){
l[i] = i - 1;
r[i] = ( i + 1 ) % ( boxnum + 1 );
}
l[0] = boxnum;
r[0] = 1;
ok = false;
while( casenum-- ){
scanf("%d",&x);
if( x == 4 ){ //反转
ok = !ok;
continue;
}
scanf("%d%d",&a,&b);
if( x == 3 && r[b] == a ) swap(a,b);
if( x != 3 && ok ) x = 3 - x;
if( (x == 1 && l[b] == a) || (x == 2 && r[b] == a) ) continue;
int la = l[a], ra = r[a], lb = l[b], rb = r[b];
if( x == 1 ){
link(la, ra);
link(a, b);
link(lb, a);
}
else if( x == 2 ){
link(la, ra);
link(b, a);
link(a, rb);
}
else if( x == 3 ){
if( ra == b ){
link(la, b);
link(b, a);
link(a, rb);
}
else{
link(la, b);
link(b, ra);
link(lb, a);
link(a, rb);
}
}
}
int t = 0;
result = 0;
for( int i = 1; i <= boxnum; i++ ){
t = r[t];
if( i % 2 != 0 ) result += t;
}
if( ok && boxnum % 2 == 0 )
result = (ULL)boxnum*(boxnum+1)/2 - result;
//cout << boxnum*(boxnum+1)/2 ;
printf("Case %d: %llu\n",++num, result);
}
return 0;
}