HDU 5860

Description

n个人编号1~n,排成一行,每一轮会从第一个人开始报数,然后每隔k-1个人报数,报到数的人会按报数的顺序被杀死,每一轮之后剩下的人重新排成一行再进行上面的过程直到所有人都被杀死。现在一共q个询问,每次询问第qi个死的人是谁。 比如7个人排成一行,1 2 3 4 5 6 7,如果k=2,那么第一轮1 3 5 7都会死,第二轮2 6会死,第三轮4会死。 

Input

输入:第一行为一个T,代表有T组测试样例,每个样例的第一行是三个整数n,k,q,(1<=n<=3000000, k>=1, q<=1000000),接下来q行,每行一个数m。 

Output

输出:对每一个询问,输出第m个死的人的编号。

Sample Input

	1
7 2 7
1
2
3
4
5
6
7

Sample Output

	1
3
5
7
2
6
4 

思路:该题可以分为两步,第一步第i个人是在第几轮死的;第二步是第i个人是在死的那一轮的第几个死的。

用s[i]表示前i轮死的人的总数,dijilun[i]表示i死的那一轮,dijige[i]表示i死的那一轮的死的序号。

那么第i个人是在第几个死的,death[i]=s[dijilun[i]]+dijige[i]

例如:第一个人是在第一轮的第一个死的death[0]=s[dijilun[0]]+dijige[0],第二个人是在第二轮的第一个死的。death[1]=s[dijilun[1]]+dijige[1];人的序号从0开始。

如果i在这一轮不死那么的它的序号就变成i-i/k-1;

之前看了很多博客发现都有个看不懂的公式dijilun[i]=i%k?dijilun[i-i/k-1]:0;个人感觉这个公式是有点问题的,正确的应该是dijilun[i]=i%k?dijilun[i-i/k-1]+1:0;

代码如下:

#include<stdio.h>
#define mm 3000300
int s[mm];//表示前i轮死了的人的和,i从0开始
int dijilun[mm];//表示在第几轮死的,i从0开始
int dijige[mm];//表示在它死的那一轮是第几个
int death[mm];//表示i死的序号;
int dead[mm];//表示第i个死的人的序号;
int solve(int n,int k)
{
    int temp,i;
    temp=n;
    s[0]=0;
    int top=0;
    while(temp)
    {
        top++;
        s[top]=s[top-1]+(temp-1)/k+1;
        temp=temp-((temp-1)/k+1);
    }
    dijilun[0]=0;
    for(i=0;i<n;i++)
    {
        dijilun[i]=i%k?dijilun[i-(i/k+1)]+1:0;//i这一轮没死,则下一轮序号为i-(i/k+1)
        dijige[i]=i%k?dijige[i-(i/k+1)]:i/k+1;
    }
    for(i=0;i<n;i++)
    {
        death[i]=s[dijilun[i]]+dijige[i];
        dead[death[i]]=i+1;//printf("%d %d\n",i+1,death[i]);
    }
}
int main()
{
    int t,i;
    scanf("%d",&t);
    while(t--)
    {
        int n,k,m;
        scanf("%d%d%d",&n,&k,&m);
        int q;
        solve(n,k);
        for(i=0;i<m;i++)
            {scanf("%d",&q);
            printf("%d\n",dead[q]);
            }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值