题目描述
题解
先贴上一波题解:
30%:直接模拟,每次暴力删除即可。时间复杂度
O(n2)
。
50%:递推计算。设F[n]表示n个人时最后剩下的人的编号。每
增 加 m-1 个 人 , 答 案 向 后 移 动 m 位 。 于 是 递 推 式 为
F[n]=F[n-m+1]%(n-m+1)+m,初始F[1]=1。时间复杂度
O(nm)
。
100%:容(da)易(biao)看出,只有
F[ma+m−1]=m
,其余的 F[n]
都满足 F[n]=F[n-m+1]+m。于是设
n=ma+(m−1)k(ma<n≤ma+1)
,那
么F[n]=km。时间复杂度
O(logmn)
。
反正我是无法da biao 找出这样的规律。。。
于是我写了个递归。
也就是说,当前有一坨人,那么这一坨人里是m的倍数的人都留下,剩下的人都出去。那么就剩下了
⌊nm⌋+n%m
个人,这样就组成了一个新的子问题,递推求解即可。每一次递归返回的是在当前状态下是第几个人赢,那么再计算一个编号就可以了。
代码
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define LL long long
LL n,m,ans;
LL find(LL t)
{
if (t<=m) return (m-1)%t+1;
LL x=t/m,y=t%m;
LL num=find(x+y);
LL loc=(x+1+num-1-1)%(x+y)+1;
if (loc<=x) return loc*m;
else return t-y+loc-x;
}
int main()
{
scanf("%lld%lld",&n,&m);
ans=find(n);
printf("%lld\n",ans);
}