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,......n,可以执行四种命令:
1 X Y 把X移到Y左边(如果X已经在Y左边,则忽略)
2 X Y 把X移到Y右边(如果X已经在Y右边,则忽略)
3 X Y 交换X和Y的位置
4 翻转整条链
经过M次变换后,求整条链奇数位的和
分析:当初想通过分奇偶数情况,用前缀和还有整体操作来求解,但是后来发现数据操作的那个部分很不好写,所以用双向链表,这也是算法竞赛入门经典(第二版)的题目P144
通过left数组和right数组和link函数实现两个节点的连接,这里的Link函数很巧妙。
这题要注意因为4操作会对1操作和2操作进行改变,所以设置一个 inv ,最后输出的时候,也会有影响。
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<string> #include<iostream> #include<cstring> #include<cmath> #include<stack> #include<queue> #include<vector> #include<map> #include<stdlib.h> #include<algorithm> #define LL __int64 #define FIN freopen("in.txt","r",stdin) using namespace std; const int MAXN=100000+5; int l[MAXN],r[MAXN]; int n,m; void link(int L,int R) //连接两个节点的link函数 { l[R]=L; r[L]=R; } int main() { int Case=0; while(scanf("%d %d",&n,&m)!=EOF) { for(int i=1;i<=n;i++) { l[i]=i-1; r[i]=(i+1)%(n+1); } l[0]=n; r[0]=1; int inv=0,opt,X,Y; while(m--) { scanf("%d",&opt); if(opt==4) inv=!inv; else { scanf("%d %d",&X,&Y); if(opt==3 && r[Y]==X) swap(X,Y); //这里要注意一下,并不是交换了X,Y的位置,而是交换了X,Y的值,以便后面进行统一处理 if(opt!=3 && inv) opt=3-opt; //这里可以看成从后往前处理 if(opt==1 && l[Y]==X) continue; if(opt==2 && r[Y]==X) continue; int LX=l[X],RX=r[X],LY=l[Y],RY=r[Y]; if(opt==1) { link(LX,RX); link(LY,X); link(X,Y); } if(opt==2) { link(LX,RX); link(Y,X); link(X,RY); } if(opt==3) { if(r[X]==Y) { link(LX,Y); link(Y,X); link(X,RY); } else { link(LX,Y); link(Y,RX); link(LY,X); link(X,RY); } } } } long long ans=0; //注意最后结果可能会很大 int b=0; for(int i=1;i<=n;i++) { b=r[b]; if(i%2==1) ans+=b; } if(inv && n%2==0) ans=(long long)(n+1)*n/2-ans; //长度为偶数,翻转后所有数的总和减去偶数项的和 printf("Case %d: %lld\n",++Case,ans); } return 0; }