HDU5860(约瑟夫环问题的变种 递推)

Death Sequence

Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 970    Accepted Submission(s): 424


 

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

 

Author

BUPT

 

Source

2016 Multi-University Training Contest 10

 

题意:n个人排成一行,从第一个人开始,每隔k个人报数,报到数的人被杀死,剩下的人重新排成一行再报数。
一共q个询问,每次询问第m个死的人是谁

【分析】

显然每一轮游戏可以看做是一个子问题(这一轮游戏建立在上一轮游戏结果的基础上 可以递推)

为了方便处理,我们假设n个人的编号为0~n-1,那么编号能被k整除的人则被杀

若某轮中某人的编号为i,如果他在此轮中没有被杀,那么在下轮中编号为i-i/k-1 然后就可以开始递推了

代码:

#include<bits/stdc++.h>
using namespace std;
int n,k,m;
struct node1
{
  int x,y,pos;//第几轮死 第几个 位置
} q[3000010];
bool cmp(node1 p1,node1 p2)
{
  if(p1.x!=p2.x)
    return p1.x<p2.x;
  return p1.y<p2.y;
}
int main()
{
  int t;
  scanf("%d",&t);
  while(t--)
  {
    scanf("%d%d%d",&n,&k,&m);
    int l=1;
    for(int i=0; i<n; i++) //从零开始编号 被k整除的人则被杀
    {
      if(i%k==0)
      {
        q[i].x=1;//第几轮死
        q[i].y=l++;//第几个死
        q[i].pos=i+1;//死的位置
      }
      else//如果这一轮第i个人死不了,下一轮他的位置是i- i/k -1
      {
        ///  满足递推关系!!!!
        q[i].x=q[i-i/k-1].x+1;
        q[i].y=q[i-i/k-1].y;
        q[i].pos=i+1;
      }
    }
    sort(q,q+n,cmp);//已排好序
    //先看轮数,再看每一轮数中的死亡顺序
    while(m--)
    {
      int x;
      scanf("%d",&x);
      printf("%d\n",q[x-1].pos);
    }
  }
  return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41668093/article/details/83065434