題目大意:
給你N個盒子,分別標號爲1~N;有下面4種操作:
“1 X Y” 表示將X移到Y的左邊;
“2 X Y” 表示將Y移到Y的右邊;
“3 X Y” 表示交換X與Y的位置;
“4” 表示將1~N所有的盒子反序。
要你求經過M次操作之後,所有奇數位置的盒子標號之和。
解題思路
大體的說一下 代碼裏有詳細註釋
當n是奇數時,操作4逆序不會影響奇數位置盒子標號之和
當n是偶數時,操作4逆序就會影響 最終結果是所有位置標號之和-奇數位置標號之和
一開始對那個swap(x,y)一直不理解
然後慢慢捋一捋 3 x,y 是交換 x,y的位置 如果當時位置是 y,x的話 就把x,y的序號互換,這樣就是把 操作轉化爲交換 y,x的位置 如果本來就是 x,y的話 就是交換xy的位置
代碼如下
#include<iostream>
using namespace std;
const int maxn=1e5+10;
int l[maxn],r[maxn];
void link(int a,int b)//讓a,b挨着
{
r[a]=b;
l[b]=a;
}
int main()
{
int n,m,x,y,flag;
int k;
int cas=0;
int i;
while(cin>>n>>m)
{
flag=0;//判斷是否翻轉
for(i=1;i<=n;i++)
{
r[i]=(i+1);
l[i]=i-1;
}
r[0]=1;
l[0]=n;
while(m--)
{
cin>>k;
if(k==4)
flag=!flag;
else
{
cin>>x>>y;
if(k==3&&r[y]==x)
swap(x,y);//方便後面統一判斷相鄰不相鄰
if(k!=3&&flag)//翻轉後所以操作動作都相反
k=3-k;
if(k==1&&l[y]==x)
continue;
if(k==2&&r[y]==x)
continue;
int lx=l[x],rx=r[x],ly=l[y],ry=r[y];
if(k==1)//x移到y左邊
{
link(lx,rx);//原來x左邊的和原來x右邊的挨着
link(ly,x);//原來y左邊的和x挨着
link(x,y);//x和y挨着
}
else if(k==2)//x移到y右邊
{
link(lx,rx);//原來x左邊的和原來x右邊的挨着
link(y,x);//y和x挨着
link(x,ry);//x和原來y的右邊的挨着
}
else{//交換x y的位置
if(r[x]==y)//x y相鄰 的話
{
link(lx,y);//原來x的左邊和y挨着
link(y,x);//y 和 x挨着
link(x,ry);//x和原來y的右邊挨着
}
else//不相鄰的話
{
link(lx,y);// 原來x的左邊和y挨着
link(y,rx);//y和原來x的右邊挨着
link(ly,x);//原來y的左邊和x挨着
link(x,ry);//x和原來y的右邊挨着
}
}
}
}
long long ans=0,num=0;
int kk=0;
for(i=1;i<=n;i++)
{
kk=r[kk];
num+=kk;
if(i%2)
ans+=(kk);
}
if(n%2==0&&flag==1)
ans=num-ans;
cas++;
cout<<"Case "<<cas<<": ";
cout<<ans<<endl;
}
return 0;
}