[BZOJbegin][NOIP十连测第七场]约瑟夫游戏(递推|数学相关|递归)

题目描述

[BZOJbegin][NOIP十连测第七场]约瑟夫游戏(递推|数学相关|递归)_第1张图片

题解

先贴上一波题解:
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+m1]=m ,其余的 F[n]
都满足 F[n]=F[n-m+1]+m。于是设 n=ma+(m1)kma<nma+1 ,那
么F[n]=km。时间复杂度 O(logmn)

反正我是无法da biao 找出这样的规律。。。
于是我写了个递归。
也就是说,当前有一坨人,那么这一坨人里是m的倍数的人都留下,剩下的人都出去。那么就剩下了 nm+n%m 个人,这样就组成了一个新的子问题,递推求解即可。每一次递归返回的是在当前状态下是第几个人赢,那么再计算一个编号就可以了。

代码

#include
#include
#include
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);
}

你可能感兴趣的:(题解,dp,数学相关)