算法与数据结构实验题 2.3 泡泡的饭碗
★实验任务
饱了吗终于发现泡泡破解了它的代码并借此白吃白喝。饱了吗当即改变了自己的幸运儿生成源码,但是,又被机智的泡泡偷瞄到了,机智的泡泡马上意识到可能要饭碗不保了:
每当有人参与抽奖,这个人就进入队列。当人数达到 n 的时候开奖一次。
1. 开奖时,将执行 m 次操作,每次操作挑一个不超过 200 的数 d,且保证 d不超过人数的一半,然后把第 D 个人和第 n-D+1 个人这两个人之间的队伍反转:
2. 反转前:1,2,…,D-1,D,D+1,…, n-D+1, n-D+2,…n(从左往右编号)
3. 反转后:1,2,…,D-1,n-D+1,n-D,…, D+1, D, n-D+2…n(这里的编号是旋转前从左到右的编号)
m 次操作完后从队头开始报号,没报到 x 的回到队尾,报到 x 的就是幸运儿啦;
机智的泡泡马上又意识到,当 n 和 m 次操作和 x 的值已知的时候,幸运儿仍然是可以预知到是第几个参与抽奖的人的。
机智的泡泡马上又意识到,自己的饭碗保住了。
但是!机智的泡泡马上意识到一个问题,这个预知结果的代码不好打。
但是!机智的泡泡马上想起了你。
机智的泡泡马上把锅又扔给了你。
★数据输入
输入第一行为三个正整数 n,m,x。
接下来 m 行,第 i 行给出第 i 次操作的 d,如题;
对于 80%的数据,2<=n<=2000,1<=m<=2000;
对于 100%的数据,2<=n<=100000,1<=m<=100000
1<=x<=1000,000,000,1<=d<=min(n/2,200);
★数据输出
输出幸运儿是第几个参加抽奖的人。
输入示例
5 2 1
2
1
输出示例
5
输入示例
5 4 3
2
1
2
1
输出示例
3
思路:
因为数据量比较大,所以如果用算法跑完整个过程,一定会超时。
根据题意,这个队列是对称反转,那么我们只需要知道所求数字有没有反转就行。因为有n个人在玩游戏,所以结果肯定是1到n,那么我们可以通过取模,直接确定是哪一个位置上的人是最终答案,再确定这个位置翻转了几次就OK。
这里的取模比较特殊,正常x%n会得到0~n-1的数字,所以我们要用(x-1)%n+1就可以得到1~n的数字
附上大佬代码:
#include<stdio.h>
int main()
{
int n,m,x,tmp;
int cnt=0; //会影响取模后的x的翻转次数
int ans;
scanf("%d%d%d",&n,&m,&x);
x = (x-1)%n+1; //取模,注意不能为0,所以是(x-1)%n+1
ans = x;
x = x<(n-x+1)?x:(n-x+1); //由于d<(n/2) 如果取模后的x在区间右边,把它变到左边来
//printf("%d\n",x);
for(int i=0;i<m;i++)
{
scanf("%d",&tmp);
if(tmp <= x) cnt++; //会影响到取模后的x
}
//printf("%d\n",cnt);
if(cnt&1){ //奇数次才会影响ans
ans = n-ans+1;
}
printf("%d\n",ans);
return 0;
}
时间复杂度为O(1)。