这道题做的人不多,而且网上凡是用递归解决的都缺少推导过程,笔者安安静静的动笔算了一遍,发现这道题的两个关键点——
希望阅读者珍惜笔者的劳动成果,转载请注明出处:
★先说递归思想:递推关系+边界条件,二者缺一不可。这道题的递推关系是根据前一轮胜利者的编号确定当前轮胜利者的编号,一直递推下去到最后一轮(也就是边界条件),胜利者在1,2,3,……,k-1,k的第k个位置上。即n==k时,返回k.
★再说整除方程(返回值的确定)。
如果你查阅相关结题报告,凡是递归解决的无外乎这样一段话:
这句话只是结论呦,推导看我的吧~
设上一轮胜利者的编号为x,当前轮胜利者的编号为y,容易推到得到这样的一个方程:y=y/k+x
式子意义是当前编号=这一轮在y之前被杀死的数量+上一轮在y之前剩下的数量x
注意,这可不是一般的方程哦,/表示的是整除,不要左右同×k,结果不等价的。
这样的方程笔者姑且叫她整除方程吧,利用不等式求解。求解思路如下:
●Step1 首先观察到y无法直接求解,不妨先求y/k,设m=y/k,则y=m+x(x已知),问题转化为求整除结果m.
●Step2 由y/k=m有,m·k+1<=y<=m·k+(k-1).为什么是m·k+1<=y而不是m·k<=y,因为y表示的是当前这轮胜利者的编号,不到最后一轮不会出现y%k==0的情况(最后一轮已经被返回了)。令y=m+x,代入得到
m·k+1<=m+x<=m·k+(k-1),原不等式组等价于
m·(k-1)<=x-1<=m·(k-1)+(k-2).
看出来没有??!!!把她反一下就可以表示为m=(x-1)/(k-1),两者表示的含义是不是等价的????!!!!Yes!!
那么m就求出来啦.则y=y/k+x=m+x=(x-1)/(k-1)+x了,参考递归代码:
参考代码+部分注释
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
#include <cstring>
#include <cmath>
#include <climits>
#define eps 1e-8
using namespace std;
typedef long long ll;
const int INF=INT_MAX;
const int maxn = 110;
int n,k;
int recursion(int n,int k)
{
if(n==k) return k; //边界条件
int x=recursion(n-n/k,k);//胜利者在下一个子序列的编号记为x
return (x-1)/(k-1)+x; //那么这一轮的编号y=y/k+x;
}
int main()
{
// freopen("input.txt","r",stdin);
int T;cin>>T;
while(T--){
cin>>n>>k;
cout<<recursion(n,k)<<endl;;
}
return 0;
}