0
点赞
收藏
分享

微信扫一扫

POJ - 2886 Who Gets the Most Candies?(单点更新,反素数)


​​POJ - 2886 Who Gets the Most Candies?​​

题目

有 n 个人坐成一个环形队列,每个人手里有一个数,指定第 k 个人开始,轮到谁谁就退出队列,如果手里的数是正数A,那么向左数A个人,反之向右数,下一轮从他开始。

如果一个人第 id 次被选中,那么他能得到的糖果数就是 id 的因子数。

问最后给出 n,k, 和所有人手里的数,求得到最多糖果数的人的名字和糖果数。

分析

不看这个游戏规则,给出 n,就能知道第几个人是要求的答案——1 到 n里因子数最多的数。

假设第 id 个人是答案,有人出队列的话位置就置为空,那么每次向左向右数人的时候只在非空位置数,可以用线段数维护非空位置模拟 id 次数人。

向左向右数的时候要先出队列。数的过程就是 mod 的一系列操作。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#define INF 0x3f3f3f3f
#define d(x) cout << (x) << endl
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1

// #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
// const ll mod = 9999991;
const int N = 5e5 + 10;
const int M = 1e6 + 10;

int tr[N << 2], divi[N], a[N];
char str[N][20];
int n, k;

// 线段树维护区间空位置数量
void build(int l=1, int r=n, int rt=1){
tr[rt] = r - l + 1;
if(l == r){
return;
}
int m = l + r >> 1;
build(lson);
build(rson);
}

int update(int l, int r, int rt, int pos){ // pos 是表示第几个空位置
tr[rt]--; // pushup 函数简写
if(l == r){
return l;
}
int m = l + r >> 1;
if(tr[rt<<1] >= pos){
return update(lson, pos); //返回的是 pos再是 a 数组第几位
}else{
return update(rson, pos-tr[rt<<1]);
}
}

void init(){ //divi 存因子数
for(int i = 1; i <= N; i++){
divi[i]++;
for (int j = 2 * i; j <= N; j+=i){
divi[j]++;
}
}
}

int cal(){ //算出第几人得到最多糖果,就是反素数
int ans = divi[1], id = 1;
for (int i = 2; i <= n; i++){
if(divi[i] > ans){
ans = divi[i];
id = i;
}
}
return id;
}

int main()
{
init();
while(~scanf("%d%d", &n, &k)){
build();
for (int i = 1; i <= n; i++){
scanf("%s%d", str[i], &a[i]);
}
int mod = n, id = cal(), t = id, pos = 0;
while(t--){ //跳 t次到id, 第一次从k开始
if(a[pos] > 0){
k = ((k - 1 + a[pos] - 1) % mod + mod) % mod + 1;
}else{
k = ((k - 1 + a[pos]) % mod + mod) % mod + 1;
}
pos = update(1, n, 1, k);
mod--; //每次出队一个人
}
printf("%s %d\n", str[pos], divi[id]);
}
return 0;
}


举报

相关推荐

0 条评论