HDU 5860 Death Sequence(递推)

HDU 5860 Death Sequence(递推)

题目链接http://acm.split.hdu.edu.cn/showproblem.php?pid=5860

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 7after the first round, 1 3 5 7 will be executed, we have2 4 6and 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

题意:

给你n个人排成一列编号,每次杀第一个人第i×k+1个人一直杀到没的杀。然后剩下的人重新编号从1~剩余的人数。按照上面的方式杀。问第几次杀的是谁。

题解:

这道题首先我们先将编号改成从0开始。这样如果i%k0那么我们可以知道第i个数字第一轮就被杀死。如果i%k!=0,那么我们知道在这之前一轮杀死了i/k+1个人。这样我们就得到递推式。

定义dp[i]代表第i轮杀死多少人。num[i]表示i在当前轮第几个被杀死。

对于i%k
0我们可以知道第一轮被杀死,所以dp[i]=0,num[i]=i/k+1。

对于i%k!=0通过前面我们知道他们的状态和i-i/k-1有关。故dp[i]=dp[i-i/k-1]+1,num[i]=num[i-i/k-1]。

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 3001000;
int dp[maxn],num[maxn],add[maxn],ans[maxn];
int n,k,q;
void init()
{
    int temp = n;
    int acl = 0;
    add[0] = 0;     //add[i]前i轮kill几个;
    while (temp){               
        acl++;
        add[acl]  = add[acl-1] + (temp-1)/k+1;   
        temp -= (temp-1)/k+1;
    }
    for (int i = 0; i < n; i++){
        if (i%k == 0){
            dp[i] = 0;
            num[i] = i/k+1;
        }else {
            dp[i] = dp[i-i/k-1] + 1; 
            num[i] = num[i-i/k-1];
        }    
    }
    for (int i = 0; i < n; i++){
        ans[add[dp[i]]+num[i]] = i; 
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while (t--){
        scanf("%d %d %d",&n,&k,&q);
        init();
        int cha;
        while (q--){
            scanf("%d",&cha);
            printf("%d\n",ans[cha]+1);
        }
    }
    return 0;    
}
posted @ 2016-08-19 20:47  Thecoollight  阅读(282)  评论(0编辑  收藏  举报