ACM模版——约瑟夫问题(出列顺序 + 最后一个)

简介: ACM模版——约瑟夫问题(出列顺序 + 最后一个)

最后一个:针对 n 范围比较大的解析


0、在公式:ans=(ans+m)%i 的基础上...当i很大,ans 和 m 都比较小的时候(i>>ans 和 m)。ans 每次增加的其实是 m。而这个增加次数可以算出来。所以...


1、当 ans + m >= i 时,普通递推。


2、当 ans + m < i 时,设增加次数为 x 次(代码中为:step 变量)。满足 ans + x * m < i + x - 1。


Ps:之所以是 x - 1,是因为 ans + m < i,ans + m + (x-1) * m < i + x -1。


3、由 2 得:x < (i - ans - 1) / (m - 1);x = ceil((i - ans - 1) / (m - 1)) - 1。


4、由 3 得:ans += x * m,i += x。


5、但如果 i 增加的总次数 (i + x) > n 了,那么最终结果应增加 (n - i + 1) * m 次,而不是 i+x 次。


/

#include<bits/stdc++.h>
#include<cmath>
#define mem(a,b) memset(a,b,sizeof a)
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
int main()
{
    ll n,m;
    while(~scanf("%lld%lld",&n,&m))
    {
        /* 最后一个:针对n范围比较小的解决方案 */
        // 编号从0开始
//        int ans=0;
//        for(int i=2;i<=n;i++)
//            ans=(ans+m)%i;
//        printf("%d\n",ans); // 输出的是数组下标
        /* 最后一个:针对n范围比较大的解决方案 HDU3089 */
        // 编号从0开始
//        ll ans=0,step=0;
//        if(m==1) ans=n-1;
//        else if(n==1) ans=0;
//        else
//        {
//            for(ll i=2;i<=n;)
//            {
//                if(ans+m<i)
//                {
                    step=(i-1-ans)%(m-1)?(i-1-ans)/(m-1):(i-1-ans)/(m-1)-1; // 等价下面这行代码
//                    step=ceil((i-1-ans)*1.0/(m-1))-1;
//                    if(i+step>n)
//                    {
//                        ans+=(n-i+1)*m; // (n-i+1)次
//                        break;
//                    }
//
//                    ans+=step*m;
//                    i+=step;
//                }
//                else
//                    ans=(ans+m)%i++;
//            }
//            ans%=n;
//        }
//
//        printf("%lld\n",ans+1); // 输出的是数组下标
        /* 出列顺序:针对出列顺序解决方案O(n*m) */
        // 编号从0开始
//        int idx=0,cnt=1,pout=0,vis[n+10];
//        mem(vis,0);
//        while(pout!=n) // out人数是否满
//        {
//            if(1==vis[idx]) // 已out
//            {
//                idx=(idx+1)%n;
//                continue;
//            }
//
//            if(cnt%m==0) // 准备out
//            {
//                vis[idx]=1;
//                pout++;
//                printf("%d\n",idx+1);
//            }
//
//            idx=(idx+1)%n; // 继续报数
//            cnt++;
//        }
        /* 针对出列顺序解决方案O(n*(logn)^2) */
        // 待更新...
    }
    return 0;
}
目录
相关文章
ACM刷题之路(十一)堆、栈、队列实现表达式转换
ACM刷题之路(十一)堆、栈、队列实现表达式转换
|
6月前
|
C++
C++刷题ACM输入数组
C++刷题ACM输入数组
69 0
|
机器学习/深度学习 算法
ACM模板——卡特兰数(Catalan)算法
ACM模板——卡特兰数(Catalan)算法
172 0
ACM模板——卡特兰数(Catalan)算法
ACM模板——排序 - 归并排序
ACM模板——排序 - 归并排序
110 0
ACM模板——排序 - 归并排序
|
存储 Java Python
ACM 选手图解 LeetCode 移除元素
给你一个数组 nums 和一个 val,原地移除所有数值等于 val 的值,并返回移除后数组的新长度。
ACM 选手图解 LeetCode 移除元素
|
Java Python
ACM 选手图解 LeetCode 二叉树的右视图
ACM 选手图解 LeetCode 二叉树的右视图
ACM 选手图解 LeetCode 二叉树的右视图
|
Java Python
ACM 选手图解 LeetCode 搜索旋转排序数组Ⅱ
ACM 选手图解 LeetCode 搜索旋转排序数组Ⅱ
ACM 选手图解 LeetCode 搜索旋转排序数组Ⅱ
|
存储 算法 Java
ACM 选手图解 LeetCode 合并二叉树
ACM 选手图解 LeetCode 合并二叉树
ACM 选手图解 LeetCode 合并二叉树
|
算法 Java Python
ACM 选手图解 LeetCode 重复的子字符串
ACM 选手图解 LeetCode 重复的子字符串
ACM 选手图解 LeetCode 重复的子字符串