哈理工OJ 1652(思维题)1652 小球移动.


小球移动
Time Limit: 1000 MS Memory Limit: 32768 K
Total Submit: 82(21 users) Total Accepted: 22(17 users) Rating:  Special Judge: No
Description
给你n个小球,从左到右编号依次为1,2,3,4,5,6.........n,并规定小球1的左边的球号为n,小球n的右边的球号为1.现在有以下3种操作:A x y表示把编号为x小球移动到编号为y的小球的左边,B x y表示把编号为x小球移动到编号为y的小球的右边,Q 1 m为询问编号为m的小球右边的球号,Q 0 m为询问编号为m的小球左边的球号。
Input
第一行有一个整数n(0<n<10000),表示有n组测试数据,随后每一组测试数据第一行是两个整数N,M,其中N表示球的个数(1<N<10000),M表示操作的的次数(0<M<10000)。
随后的M行,每行有三个数 s x y,s表示操作的类型,x,y为小球号。当s为Q时,若x为1,则询问小球y右边的球号,x为0,则询问小球y左边的球号。
Output
输出每次询问的球号。
Sample Input
1
6 3
A 1 4
B 3 5
Q 1 5
Sample Output
3


炸一看题,这么多次询问 一定是线段树咯~。但是感觉链表也能实现,而且思路简单的多。但是我这个题看了一下提交状态,跑的最快的程序竟然只跑了1ms.看的我目瞪口呆,赶紧看了大牛的代码,刚开始理解还是比较难理解的,但是之后自己默默的推敲了一番,发现这种做法还是很奇妙的。

大牛永远都是大牛,小白只能仰望,然后膜拜。然后虚心学习,说不定真有一天就有小白这样崇拜你了呢~!!!!

这里废话不多说,题目是中文的 ,这里不进行题目大意的解释,直接讨论操作:
1.A操作.将a小球挪到b小球的左边:(A,1,4做为例子)
我们这里先举出实例:
序列长度为6的起始数组:

1 2 3 4 5 6.

这里我们再定义一个左右数组,用来存编号为i的小球的左,右分别为什么编号的小球:
比如对开始数组的初始化如下:

int xulie[10005];
int zuo[10005];
int you[10005];
         for(int i=1;i<=n;i++)//这里n代表有n个小球~.
         {
             xulie[i]=i;
         }
         for(int i=1;i<=n;i++)//还是比较好理解的哈~~~~
         {
             if(i==1)
             zuo[i]=xulie[n];
             else
             zuo[i]=xulie[i-1];
         }
         for(int i=1;i<=n;i++)
         {
             if(i==n)
             you[i]=xulie[1];
             else
             you[i]=xulie[i+1];
         }


挪动之后变成了:

2 3 1 4 5 6

这个时候我们先抛弃链表思维,直接观察变化:

1从原来的位子改变到了4的左边,这个时候.有以下变化量:

2左.

6左.

3右.

4左.

1左.

1右.

拿出第一个例子来说 ,原来2的左边是1 现在变成了6.

拿出第二个例子来说,原来6的左边是1现在变成了2.

拿出第三个例子来说,原来3的右边是4现在变成了1.

...

...

...

依次类推,我们得到了这样的一个变化关系.

这个时候我们先不要整理思路,因为我们现在只考虑了a操作。不急着写代码,我们这里再考虑b操作

2.B操作.将a小球挪到b小球的右边:(A,1,4做为例子)

原先的序列依旧是:

1 2 3 4 5 6 

挪动之后是:

2 3 4 1 5 6

我们按照刚刚的思维,1从原来的位子改变到了4的右边,这个时候.有以下变化量:

2左.

6右.

5左.

4右.

1左.

1右.

这个时候我们整合思路:无论是1挪到4的左边还是右边,都有六个变化量,这个结论绝壁不是巧合,不信的小伙伴自行多列实例来观察变化.

这个时候我们有了结论,然后用代码模拟操作a就行了:

void caozuoa(int a,int b)
{
    you[zuo[a]]=you[a];//6的右边变成2
    zuo[you[a]]=zuo[a];//2的左边变成6
    you[zuo[b]]=xulie[a];//依次类推.
    zuo[a]=zuo[b];
    you[a]=xulie[b];
    zuo[b]=xulie[a];
}

然后我们再模拟操作b:
void caozuob(int a,int b)
{
    you[zuo[a]]=you[a];
    zuo[you[a]]=zuo[a];
    zuo[you[b]]=xulie[a];
    you[a]=you[b];
    zuo[a]=xulie[b];
    you[b]=xulie[a];
}

然后补全主函数:

#include<stdio.h>
#include<string.h>
using namespace std;
int xulie[10005];
int zuo[10005];
int you[10005];
void caozuoa(int a,int b)
{
    you[zuo[a]]=you[a];
    zuo[you[a]]=zuo[a];
    you[zuo[b]]=xulie[a];
    zuo[a]=zuo[b];
    you[a]=xulie[b];
    zuo[b]=xulie[a];
}
void caozuob(int a,int b)
{
    you[zuo[a]]=you[a];
    zuo[you[a]]=zuo[a];
    zuo[you[b]]=xulie[a];
    you[a]=you[b];
    zuo[a]=xulie[b];
    you[b]=xulie[a];
}
int main()
{
     int t;
     scanf("%d",&t);
     while(t--)
     {
         int n,x;
         scanf("%d%d",&n,&x);
         getchar();
         for(int i=1;i<=n;i++)
         {
             xulie[i]=i;
         }
         for(int i=1;i<=n;i++)
         {
             if(i==1)
             zuo[i]=xulie[n];
             else
             zuo[i]=xulie[i-1];
         }
         for(int i=1;i<=n;i++)
         {
             if(i==n)
             you[i]=xulie[1];
             else
             you[i]=xulie[i+1];
         }
		for(int j=0;j<x;j++)
		{
		    char c;
		    int a,b;
			scanf("%c %d %d",&c,&a,&b);
			getchar();
			if(c=='A')
			{
				caozuoa(a,b);
			}
			if(c=='B')
			{
				caozuob(a,b);
			}
			if(c=='Q')
			{
				if(a==1)
					printf("%d\n",you[b]);
				else
					printf("%d\n",zuo[b]);
			}
		}
     }
}



















你可能感兴趣的:(哈理工1652,哈理工OJ1652)