题目链接:传送门
题目描述:
题目描述 即使tmk上了大学,tmk还是十分怀念以前的高中生活还有以前的小伙伴们。 Tmk还记得在高考前几天,tmk和他的小伙伴们参加了ht的生日party。在某个时间点,需要选出一个唱歌的人,于是tmk提议说不如我们来玩一次约瑟夫问题吧。 我们有n个人排成一列,首先从头到尾报数1,2,3…..n,报到m的倍数的人出列,接下来从尾到头报数,报到m的倍数的人出列。直到人数小于m,这时再报一次数,报到1的人就被选出来唱歌。 现在问谁是出来唱歌的人
输入 首先第一个数T,T<=10,表示数据组数。 每组数据,第一行有两个数,n和m(1<=n<=10000,1<m<=1000000),分别表示询问数和题目中的m 接下来有n行,每行一个数x(1<x<=1000000),表示一个询问,即问x个人排成一列,原编号为多少的人会被选出来唱歌。
输出 对于每组数据,输出n行,每行一个整数,第i行的整数表示第i个询问的答案
样例输入 2 样例输出: 1 4 1 5 |
题解,思路写在代码里面。
递归:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int n, m;
// 假设一个序列 一共 7人 A: 1, 2, 3, 4, 5, 6 ,7
// m = 3
// 第一次出列 队列只剩下5人:
// 1, 2, 4, 5, 7
// 因为第二次要从尾部开始数:
// 队列应为 B: 7, 5, 4, 2, 1
// BchangeintoA() 函数是将求得 "数组B中下标为 i的人" 在 "数组 A中的下标"
// 下标 从 1 开始
// 例如 7, 在B中的下标为 1, 在A中下标为 7
// 例如 2, ............. 4, ........... 2
// alen 数组A 的长度
int BchangeintoA(int alen, int i, int blen) {
i = blen+1 - i;
int temp = i + (i-1)/(m-1);
return temp;
}
const int N = 1000100;
int F[N]; // F[N] 不为-1 则表示如果队列为N,唱歌的人的编号
// Example: F[2] = 1 , 如果序列长度为2,编号为1的 人唱歌
// 所有人下标从1开始
int Work(int num) {
// 函数f 是去求解f[num],即队列中的人数 为num时唱歌的人的编号
if(F[num] != -1) {
return F[num];
}
if(num < m){
F[num] = 1;
return 1;
}
Work(num-num/m);
// 减而治之,例如如果是 7 个人的队列,在数一遍之后只剩下五个人
F[num] = BchangeintoA(num, F[num-num/m], num-num/m);
// num >= m : 每一个F[num] 都是有 F[num-num/m] 推过来
// for(int i=1; i<=num; i++) {
// cout << F[i] << " ";
// }
// cout << endl;
return F[num];
}
int main(){
int T;
cin >> T;
for(int t=1; t<=T; t++) {
cin >> n >> m;
memset(F, -1, sizeof(F)); // 对 f 进行初始化
int x;
for(int i=1; i<=n; i++) {
scanf("%d",&x);
printf("%d\n",Work(x));
}
}
return 0;
}
递推:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N = 1000100;
int F[N];
int n, m;
int BchangeintoA(int alen, int i, int blen) {
i = blen+1 - i;
int temp = i + (i-1)/(m-1);
return temp;
}
int main(){
int T;
cin >> T;
for(int t=1; t<=T; t++) {
cin >> n >> m;
memset(F, -1, sizeof(F)); // 对 f 进行初始化
for(int i=1; i<m; i++) {
F[i] = 1;
}
int x;
int max = m-1;
for(int i=1; i<=n; i++) {
scanf("%d",&x);
if(x <= max) {
printf("%d\n",F[x]);
}
else {
for(int i=max+1; i<=x; i++) {
F[i] = BchangeintoA(i, F[i-i/m], i-i/m);
}
max = x;
printf("%d\n",F[max]);
}
// for(int i=1; i<=max; i++){
// printf("%d ",F[i]);
// }
// printf("\n");
}
}
return 0;
}