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 41 1 42 3 53 1 646 31 1 42 3 53 1 6100000 14
Sample Output
Case 1: 12Case 2: 9Case 3: 2500050000 一年后重写这道题 给个容易理解的版本吧:#include<iostream> #include<cstdio> #include<cstring> #define left leftt #define right rightt #define maxn 100050 using namespace std; int left[maxn<<2],right[maxn<<2]; int n; void init() { for(int i=0;i<=n+10;i++) { left[i]=i-1; right[i]=i+1; } } void move_to(int a,int b,int d) { int la,lb,ra,rb; la=left[a],lb=left[b]; ra=right[a],rb=right[b]; if((ra==b&&d==1)||(rb==a&&d==2)) return; right[la]=ra; left[ra]=la; if(d==1){ left[a]=lb; right[a]=b; left[b]=a; right[lb]=a; } else { right[a]=rb; left[a]=b; right[b]=a; left[rb]=a; } } void Swap(int a,int b) { int la,lb,ra,rb; la=left[a],lb=left[b]; ra=right[a],rb=right[b]; if(ra==b){ move_to(a,b,2); return; } else if(la==b) { move_to(a,b,1); return; } left[a]=lb; right[a]=rb; left[rb]=a; right[lb]=a; left[b]=la; right[b]=ra; left[ra]=b; right[la]=b; } int main() { int m,op,a,b; int flag; int pos; int Case=1; long long ans; while(~scanf("%d%d",&n,&m)) { init(); ans=0; flag=0; while(m--) { scanf("%d",&op); if(op==4) flag=1-flag; else { scanf("%d%d",&a,&b); if((op==1&&!flag)||(op==2&&flag)) move_to(a,b,1); else if((op==1&&flag)||(op==2&&!flag)) move_to(a,b,2); else if(op==3) Swap(a,b); } } if(!flag) { pos=0; while(pos<=n) { pos=right[pos]; if(pos>n) break; ans+=pos; pos=right[pos]; } } else if(flag) { pos=n+1; while(pos>0) { pos=left[pos]; ans+=pos; pos=left[pos]; } } printf("Case %d: %lld\n",Case++,ans); } return 0; }
代码:#include <iostream> #include <cstdio> #include <cstring> #define maxn 1001000 #define ll long long using namespace std; int next[maxn],pre[maxn],n,m,k,tim; int *tep,*tep2; void init_next_pre() { for (int i=1; i<=n; i++) next[i]=i+1,pre[i]=i-1; next[n]=0; } void dele(int x) { int k1=pre[x],k2=next[x]; next[k1]=k2,pre[k2]=k1; } void insert(int k1,int mid,int k2) { next[k1]=mid,next[mid]=k2; pre[k2]=mid,pre[mid]=k1; } void SWAP(int x,int y) { int k1=pre[x],k2=next[x],k3=pre[y],k4=next[y]; if (k2==y) //如果x,y相邻(有两种情况) { next[k1]=y,next[y]=x,next[x]=k4; pre[k4]=x,pre[x]=y,pre[y]=k1; } else if (k4==x) { next[k3]=x,next[x]=y,next[y]=k2; pre[k2]=y,pre[y]=x,pre[x]=k3; } else { next[k1]=y,next[y]=k2,pre[y]=k1,pre[k2]=y; next[k3]=x,next[x]=k4,pre[x]=k3,pre[k4]=x; } } int main() { int cod,x,y,cas=0; while (cin>>n>>m) { tim=0; init_next_pre(); //初始化 while (m--) { cin>>cod; if (cod==4) tim++; else { cin>>x>>y; if (cod<3 && tim&1) //当前翻转次数为奇数次时 .. cod=3-cod; if (cod==1) { dele(x); k=pre[y]; insert(k,x,y); } else if (cod==2) { dele(x); k=next[y]; insert(y,x,k); } else if (cod==3) SWAP(x,y); } } if (tim&1) tep=pre,tep2=next; //优化 最多只需反转一次 else tep=next,tep2=pre; //将数组地址赋给指针 for (int i=1; i<=n; i++) { if (tep2[i]==0) { ll ans=0; for (int k=1; i; i=tep[i],k++) if (k&1) ans+=i; cout<<"Case "<<++cas<<": "<<ans<<endl; break; } } } return 0; }
LIST解法 不过可惜超时了#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<list> #include<algorithm> using namespace std; typedef list<int>list1; list1 q; int main() { list1::iterator ii; list1::iterator jj; int ss; int m,n,i,j; int a,b,mm; long long s; int t=0; while(~scanf("%d%d",&m,&n)) { ss=0; t++; q.clear(); for(i=1; i<=m; i++) q.push_back(i); while(n--) { scanf("%d",&mm); if(mm!=4) { if(ss&1) mm=3-mm; scanf("%d%d",&a,&b); ii=find(q.begin(),q.end(),a); jj=find(q.begin(),q.end(),b); if(mm==1) { q.erase(ii); q.insert(jj,a); } else if(mm==2) { q.erase(ii); q.insert(++jj,a); } else if(mm==3) { swap(*ii,*jj); //神奇的SWAP } } else { ss++; } } i=1; s=0; if(ss%2==1) q.reverse(); printf("Case %d: ",t); for(ii=q.begin(); ii!=q.end(); ii++) { if(i%2==1) s=s+*ii; i++; } cout<<s<<endl; } return 0; }