题解 UVA12657 【移动盒子 Boxes in a Line】
首先如果用数组来保存盒子,肯定会超时。
解决办法是采用链表,把每个盒子编号存起来。
可是普通的链表无法满足此题的要求。
解决方法是采用双向链表:用
下面的过程可以让两个结点相互连接:
void link(int L,int R)
{
r[L]=R;
l[R]=L;
}
这样就可以先记录好操作之前 X 和 Y 两边的结点,然后用link函数按照某种顺序把它们连起来。
由于操作四如果直接进行操作,就会不可避免地 TLE .
可以增加一个标记 flag 表示有没有执行过操作4(如果flag=1 时再执行一次操作4,则 flag 变为0)。这样,当 o (o为操作) 为1和2且 flag=1 时,只需把 o 变成 3-o (注意操作3不受 flag 影响)即可。最终输出时要根据 flag 的值进行不同处理。
示例代码:
#include <bits/stdc++.h>
using namespace std;
int n,m;
int l[100005],r[100005];
void link(int L,int R) //连接
{
r[L]=R;
l[R]=L;
}
int main()
{
int Case=0;
while(cin>>n>>m)
{
for(int i=1;i<=n;i++) //初始化链表
{
l[i]=i-1;
r[i]=(i+1)%(n+1); //注意此处处理
}
r[0]=1;
l[0]=n; //首尾连接
int o,x,y,flag=0;
while(m--)
{
cin>>o; //输入运算符
if(o==4) //操作四,对 flag操作
{
flag=!flag;
}
else
{
cin>>x>>y;
if(o==3&&r[y]==x) //此处是为了方便后面统一处理
{
swap(x,y);
}
if(o!=3&&flag) //更改操作
{
o=3-o;
}
if(o==1&&x==l[y]) //已经是了
{
continue;
}
if(o==2&&x==r[y]) //同上
{
continue;
}
int lx=l[x],rx=r[x],ly=l[y],ry=r[y]; //定义一些后面所需的变量
if(o==1) //这些连接具体操作可以试着在纸上画一画清晰思路
{
link(lx,rx);
link(ly,x);
link(x,y);
}
else if(o==2)
{
link(lx,rx);
link(y,x);
link(x,ry);
}
else if(o==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);
}
}
}
}
int t=0;
long long ans=0;
for(int i=1;i<=n;i++)
{
t=r[t];
if(i%2==1) //这里统计奇数位置编号和
{
ans+=t;
}
// cout<<ans<<endl;
}
if(flag&&n%2==0) //如果被反转了并且 n 是偶数(具体为什么也可在纸上试着画画)
{
ans=(long long)(1+n)*n/2-ans; //答案应为另一部分(注意前面为等差数列求和公式)
}
// cout<<ans<<endl;
cout<<"Case "<<++Case<<": "<<ans<<endl;
}
return 0;
}