洛谷 P1145:[CERC 1995] 约瑟夫 ← 队列 + 优化

【题目来源】
https://www.luogu.com.cn/problem/P1145

【题目描述】
2k 个人站成一圈,从某个人开始数数,每次数到 m 的人就被杀掉,然后下一个人重新开始数,直到最后只剩一个人。现在有一圈人,k 个好人站在一起,k 个坏人站在一起。从第一个好人开始数数。你要确定一个最小的 m,使得在 k 个坏人均被杀死时 k 个好人都存活。

【输入格式】
一行一个整数 k。

【输出格式】
一行一个整数 m。

【输入样例一】
3

【输出样例一】
5

【输入样例二】
4

【输出样例二】
30

【数据范围】
0<k<14。

【算法分析】
● 注意题目中的关键陈述“k 个好人站在一起,k 个坏人站在一起。从第一个好人开始数数”,这个代码会直接体现。

● 由于所有人始终围成一圈进行报数,当报数次数恰好等于当前队列总人数时,相当于绕圈一周后回到起点。因此在如下代码中模拟报数过程时,不必真的执行完整的 m-1 次移动操作,只需通过取模运算 (m-1) % len 计算出有效偏移步数,直接跳过所有绕圈的冗余操作。这一优化能将原本可能高达数万次的循环骤减为最多几十次,大幅降低时间开销,从而避免程序超时。​​​​​​​--- 这就是这道题必须加、不加必超时(TLE)的优化策略!

【算法代码】

#include <bits/stdc++.h>
using namespace std;

bool check(int k,int m) {
    queue<int> q;
    //First good k people, then bad.
    for(int i=1; i<=2*k; i++) q.push(i);

    for(int i=1; i<=k; i++) { //Kill k bad.
        int len=q.size();
        int step=(m-1)%len;
        for(int j=0; j<step; j++) {
            q.push(q.front());
            q.pop();
        }

        //Dequeue the mth element
        int t=q.front();
        q.pop();
        //If killed good, failure.
        if(t<=k) return false;
    }
    return true;
}

int main() {
    int k,m=1;
    cin>>k;
    while(true) {
        if(check(k,m)) {
            cout<<m<<endl;
            break;
        }
        m++;
    }

    return 0;
}

/*
in:3
out:5
*/

 

【参考文献】
https://blog.csdn.net/hnjzsyjyj/article/details/149135096
https://blog.csdn.net/hnjzsyjyj/article/details/108410252
https://blog.csdn.net/hnjzsyjyj/article/details/127023239
https://blog.csdn.net/hnjzsyjyj/article/details/133636109

posted @ 2026-03-25 10:40  Triwa  阅读(2)  评论(0)    收藏  举报