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;
}