2019ICPC南昌网络赛 - E. Magic Master

题意:

首先一号位置上必为 1,剩下的 n - 1 张牌转化为约瑟夫环问题,共有 n - 1 个人,每数 m + 1 个数淘汰一人,共有 q 次询问,每次询问求第 k 个人是第几个被淘汰的。(n, k <= 40000000, m <= 10, q <= 100)

链接:

https://nanti.jisuanke.com/t/41352

题解:

首先约瑟夫环有线性 O(n) 做法,但是考虑到可能过不了,注意到 m 很小,这种情况下一圈下去可以淘汰 n / m 个人,规模可以小得多,原理还是跟线性的一样,但复杂度可证明为 O(mlogn)。

参考代码:
#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define sz(a) ((int)a.size())
#define mem(a, b) memset(a, b, sizeof a)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e6 + 5;
const int maxm = 2e6 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

int n, m, q;

int dfs(int n, int k){

	if(n == 1) return 1;
    if(n < m){

		if(k == (m - 1) % n) return 1;
		int np = m % n;
        k = (n - np + k - (k >= np)) % (n - 1);
		return dfs(n - 1, k) + 1;
    }
	if((k + 1) % m == 0) return (k + 1) / m;
	int np = n - n % m;
	k = (n - np + k - k / m) % (n - 1);
	return dfs(n - n / m, k) + n / m;
}

int main(){

    int t; scanf("%d", &t);
    while(t--){

        scanf("%d%d%d", &n, &m, &q); --n, ++m;
        while(q--){

            int k; scanf("%d", &k);
            if(k == 1) { printf("1\n"); continue; }
            int ret = dfs(n, k - 2) + 1;
            printf("%d\n", ret);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值