Description
你有一行盒子,从左到右依次编号为1, 2, 3,…, n。你可以执行四种指令:
1 X Y表示把盒子X移动到盒子Y左边(如果X已经在Y的左边则忽略此指令)。
2 X Y表示把盒子X移动到盒子Y右边(如果X已经在Y的右边则忽略此指令)。
3 X Y表示交换盒子X和Y的位置。
4 表示反转整条链。
指令保证合法,即X不等于Y。例如,当n=6时在初始状态下执行1 1 4后,盒子序列为2 3 1 4 5 6。接下来执行2 3 5,盒子序列变成2 1 4 5 3 6。再执行3 1 6,得到2 6 4 5 3 1。最终执行4,得到1 3 5 4 6 2。
Input
输入包含不超过10组数据,每组数据第一行为盒子个数n和指令条数m(1<=n,m<=100,000),以下m行每行包含一条指令。
Output
每组数据输出一行,即所有奇数位置的盒子编号之和。位置从左到右编号为1~n。
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
#include<cstdio> #include<algorithm> using namespace std; const int maxn = 100000 + 5; int n, left[maxn], right[maxn]; //记住每个盒子相邻的盒子的序号; inline void link(int L, int R)
{ right[L] = R; left[R] = L; } 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; //当遇到‘4’指令时;先不处理; else { scanf("%d%d", &X, &Y); if(op == 3 && right[Y] == X) swap(X, Y); if(op != 3 && inv) op = 3 - op; //若果‘4’指令个数为奇数,那么将‘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(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; }