题目链接
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开始向后输出,或者说顺时针输出
}
}
}
}
}

京公网安备 11010502036488号