2016多校训练Contest10: 1004 Death Sequence hdu5860

本文介绍了一种约瑟夫问题的变形及其高效求解方法。问题设定为一定数量的人站成一排,按特定步长逐个淘汰直至无人幸存,并要求输出淘汰顺序。文章提出了一种通过预处理数据实现快速查询的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem Description
You may heard of the Joseph Problem, the story comes from a Jewish historian living in 1st century. He and his 40 comrade soldiers were trapped in a cave, the exit of which was blocked by Romans. They chose suicide over capture and decided that they would form a circle and start killing themselves using a step of three. Josephus states that by luck or maybe by the hand of God, he and another man remained the last and gave up to the Romans.

Now the problem is much easier: we have N men stand in a line and labeled from 1 to N, for each round, we choose the first man, the k+1-th one, the 2*k+1-th one and so on, until the end of the line. These poor guys will be kicked out of the line and we will execute them immediately (may be head chop, or just shoot them, whatever), and then we start the next round with the remaining guys. The little difference between the Romans and us is, in our version of story, NO ONE SURVIVES. Your goal is to find out the death sequence of the man.

For example, we have N = 7 prisoners, and we decided to kill every k=2 people in the line. At the beginning, the line looks like this:

1 2 3 4 5 6 7

after the first round, 1 3 5 7 will be executed, we have

2 4 6

and then, we will kill 2 6 in the second round. At last 4 will be executed. So, you need to output 1 3 5 7 2 6 4. Easy, right?

But the output maybe too large, we will give you Q queries, each one contains a number m, you need to tell me the m-th number in the death sequence.
 

Input
Multiple cases. The first line contains a number T, means the number of test case. For every case, there will be three integers N (1<=N<=3000000), K(1<=K), and Q(1<=Q<=1000000), which indicate the number of prisoners, the step length of killing, and the number of query. Next Q lines, each line contains one number m(1<=m<=n).
 

Output
For each query m, output the m-th number in the death sequence.
 

Sample Input
1 7 2 7 1 2 3 4 5 6 7
 

Sample Output
1 3 5 7 2 6 4

因为是取第一个和所有%k==1的人,所以我们考虑把第一个人的下表订成0,这样出队的人就是%k==0的了

然后考虑%k!=0的人,假设为i,那么他的状态是和i-i/k-1的人一样的

因为i-i/k-1<i,我们是从1推到i的,所以i-i/k-1肯定已经被处理过,我们直接在出队轮数+1即可

最后按照处理出来的构造出出队序列,O(1)询问即可

#include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int list[3000001],rk[3000001];
int sum[3000001],que[3000001];
int main()
{
	int T;
	scanf("%d",&T);
	while(T>0)
	{
		T--;
		int n,k,q;
		scanf("%d%d%d",&n,&k,&q);
		int i;
		memset(sum,0,sizeof(sum));
		list[0]=1;
		rk[0]=0;
		sum[1]=1;
		int tot=1;
		for(i=1;i<=n-1;i++)
		{
			if(i%k==0)
			{
				list[i]=1;
				rk[i]=i;
				sum[1]++;
			}
			else
			{
				int j=i-i/k-1;
				list[i]=list[j]+1;
				rk[i]=rk[j];
				sum[list[i]]++;
				tot=max(tot,list[i]);
			}
		}
		for(i=1;i<=tot;i++)
			sum[i]+=sum[i-1];
		for(i=0;i<=n-1;i++)
			que[sum[list[i]-1]+rk[i]/k+1]=i+1;
		int x;
		for(i=1;i<=q;i++)
		{
			scanf("%d",&x);
			printf("%d\n",que[x]);
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值