题目链接
https://ac.nowcoder.com/acm/contest/8564/F
解题思路
很多同学是不是没理解题目,画个图(其中f表示翻转次数,f=1表示翻转奇数次,f=0表示翻转偶数次):
大致思路:
数据结构啊,用结构体数组模拟链表。因为涉及类似节点移动的操作,用线性表时间复杂度太高,这时候链表的优势就发挥出来了。模拟过程就好。
详细思路:
建立结构体数组information[i],内含两个变量before和after,分别指向i节点的前面节点和后面节点;
注:我们模拟的时候是不进行彻头彻尾的翻转操作的,因为太浪费时间了,我们不妨记录下来是否发生了翻转,翻转后的插入操作是将“x插于y前”“x插于y后”分别变成了“x插于y后”“x插于y前”;翻转前的插入操作正常进行。
输出的时候,当f=1时,我们输出before,相当于逆时针输出;当f=0时,我们输出after,相当于顺时针输出。
抱歉,我表达能力太差了……
稍微说一下,我当时是怎么想到的:
首先想到用结构体模拟链表;
之后,觉得题目让怎么插入我就怎么修改,直接记录下来是否翻转(就是翻转次数的奇偶),输出的时候根据标记选择顺时针输出还是逆时针输出就ok了。
但是,wa了,举了个反例发现了错误,比如先进行翻转操作,再进行移动操作,发现与正确的输出有差别。
而且发现差别不大,仿佛就是翻转后导致插入的时候有点问题,我就将“向后/前插”调整为“向前/后插”,完美AC!
我感觉这里才是最难想的地方。至于移动操作,虽然代码长,但是我觉得学过数据结构的应该都能自己写,反而看别人的代码可能理解起来更慢。
AC代码
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=1e4+100; int f,n,m,op,x,y,tt,pp; struct INF { int be,af; }inf[N]; /* //for testing void output() { int mm=n,pp=1; while(mm--) { printf("%d%c",pp,mm?' ':'\n'); pp=inf[pp].af; } } */ void putbefore(int,int,int);//提前声明一下,要不编译不了 void putafter(int ff,int xx,int yy) { if(ff) putbefore(0,xx,yy);//发生过翻转后把x放到y后面 相当于 发生翻转前把x放到y前面,输出时能保证是正确的 //这里把f当成参数传入是防止putbefore和putafter循环调用导致死循环,下同 else { inf[inf[x].af].be=inf[x].be;//让x的 后继节点 的 前驱节点指针 指向x的 前驱节点 inf[inf[x].be].af=inf[x].af;//让x的 前驱节点 的 后继节点指针 指向x的 后继节点 inf[x].af=inf[y].af;//让x的 后继节点指针 指向y的 后继节点 inf[x].be=y;//让x的 前驱节点指针 指向y inf[inf[y].af].be=x;//让y的 后继节点 的 前驱节点指针 指向x inf[y].af=x;//让y的 后继节点指针 指向x } } void putbefore(int ff,int xx,int yy) { if(ff) putafter(0,xx,yy);//发生过翻转后把x放到y前面 相当于 发生翻转前把x放到y后面,输出时能保证是正确的 else { //类似与上面 inf[inf[x].af].be=inf[x].be; inf[inf[x].be].af=inf[x].af; inf[x].be=inf[y].be; inf[x].af=y; inf[inf[y].be].af=x; inf[y].be=x; } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) inf[i].be=(i==1?n:i-1),inf[i].af=(i==n?1:i+1);//初始化 // for(int i=1;i<=n;i++) cout<<i<<' '<<inf[i].be<<' '<<inf[i].af<<endl;//for testing while(m--) { scanf("%d",&op); if(op==1) { scanf("%d%d",&x,&y); putafter(f,x,y);//把x放到y的后面,但是要注意是否发生翻转,详见函数代码注释 // for(int i=1;i<=n;i++) cout<<i<<' '<<inf[i].be<<' '<<inf[i].af<<endl;//for testing // output();//for testing } else if(op==2) { scanf("%d%d",&x,&y); putbefore(f,x,y);//把x放到y的前面,但是要注意是否发生翻转,详见函数代码注释 // for(int i=1;i<=n;i++) cout<<i<<' '<<inf[i].be<<' '<<inf[i].af<<endl;//for testing // output(); //for testing } else if(op==3) //reverse { f^=1;//标记翻转 } else //print { tt=n;pp=1; if(f) { while(tt--) { printf("%d%c",pp,tt?' ':'\n'); pp=inf[pp].be;//发生过奇数次翻转,从1开始向前输出,或者说逆时针输出 } } else { while(tt--) { printf("%d%c",pp,tt?' ':'\n'); pp=inf[pp].af;//发生过偶数次翻转,从1开始向后输出,或者说顺时针输出 } } } } }