poj 2886 Who Gets the Most Candies?

Who Gets the Most Candies?
Time Limit: 5000MS   Memory Limit: 131072K
Total Submissions: 14264   Accepted: 4504
Case Time Limit: 2000MS

Description

N children are sitting in a circle to play a game.

The children are numbered from 1 to N in clockwise order. Each of them has a card with a non-zero integer on it in his/her hand. The game starts from the K-th child, who tells all the others the integer on his card and jumps out of the circle. The integer on his card tells the next child to jump out. Let A denote the integer. If A is positive, the next child will be the A-th child to the left. If A is negative, the next child will be the (A)-th child to the right.

The game lasts until all children have jumped out of the circle. During the game, the p-th child jumping out will get F(p) candies where F(p) is the number of positive integers that perfectly divide p. Who gets the most candies?

Input

There are several test cases in the input. Each test case starts with two integers N (0 < N ≤ 500,000) and K (1 ≤ KN) on the first line. The next N lines contains the names of the children (consisting of at most 10 letters) and the integers (non-zero with magnitudes within 108) on their cards in increasing order of the children’s numbers, a name and an integer separated by a single space in a line with no leading or trailing spaces.

Output

Output one line for each test case containing the name of the luckiest child and the number of candies he/she gets. If ties occur, always choose the child who jumps out of the circle first.

Sample Input

4 2
Tom 2
Jack 4
Mary -1
Sam 1

Sample Output

Sam 3

题意:有N个小孩,排成一个圆圈,编号从1开始,分别为1,2,3,...,N,每个人手中都有一个牌子,牌子上写着一个整数,如果目前的这一轮有一个孩子出了圆圈,那么下一个出圆圈的小孩的编号就是目前出圆圈的小孩的编号加上他牌子上写的整数。每有一个小孩出了圆圈,他将会获得
一定数量的糖果,假设当前小孩是第k个出圆圈的,那么获得的糖果的数量等于k的因子的个数,'1'也算。问拿到糖果数最多的是哪个小孩,拿了多少糖果。
思路:首先需要制定一份因子表factor_num[N],用于记录每一个数的因子的个数.做法类似于埃氏筛选。从小到大找素数,每找到一个素数,这个素数都有可能是比这个素数大的那些数的因子,每找到一个比当前素数大的并且能整除该素数的数,判断这个数中包含了多少当前素数因子。
(108=3*3*3*2*2,所以它的素数因子为{1,3,9,27}*{1,2,4},一共有4*3个因子)
之后就是如何模拟小孩出圈的问题了,这个可以用树状数组来记录更新情况,树状数组维护的是每个小孩初始编号下的值,这个值为1,说明这个初始编号下的小孩还在圈中,若为0,则代表这个初始编号下的小孩已经离开圆圈。现在我们假设小孩的初始编号从0开始,这样方便每次计算下一个
需要出圆圈的小孩的初始编号。这样,若当前还在圈中的一个小孩的初始编号是K,那么树状数组中的sum(K)代表的含义是:初始编号在K之前的小孩还剩多少个在圈子里,或者可以说初始编号是K的小孩是当前剩下的第sum(K)+1个小孩(因为树状数组记录编号是从1开始的,小孩初始编号从0开始,
故sum(K)记录初始编号小于K的数中值的和)。利用刚才所说的树状数组,可以建立一种映射关系,如果我们已经知道某一个还在圈中的小孩的位置(他是剩下小孩中的第几个),设为第x个(下标从0记录,意味着在该小孩前面还有x个小孩),那么可以二分的查找他的初始下标,直至找到这么一个初始
下标k,使得sum(k)==x。则找到了这个初始下标K后,即可进行下一次的循环。共N次循环,找到拿到糖果数最多的小孩。
AC代码:
#define _CRT_SECURE_NO_DEPRECATE
#include
#include
using namespace std;
const int N_MAX = 500000 + 4;
char name[N_MAX][11];
int number[N_MAX];
int factor_num[N_MAX+16];

void init_factor_num(int n) {
    fill(factor_num, factor_num + n+1, 1);
    for (int i = 2; i <= n; i++) {
        if (factor_num[i] == 1) {//每一个挑选出来的i都是质数的话就可当除数因子
            for (int j = i; j <= n; j += i) {
                int k = 0;
                for (int m = j; m%i == 0; m /= i, k++);
                factor_num[j] *= k + 1;//+1是因为因子1也要算上!!!!!!!!
            }
        }
    }
}

class BItree {
public:
    int size;
    int bit[N_MAX];
    BItree(){}
    void init_BIT(int size) {
        this->size = size;
        memset(bit,0,sizeof(bit));
    }
    int sum(int i) {
        int s = 0;
        while (i>0) {
            s += bit[i];
            i -= i&-i;
        }
        return s;
    }
    void add(int i, int v) {
        i++;//编号i是从0开始记录的,树状树组从1开始记录,对应加1即可
        while (i <= N_MAX) {
            bit[i] += v;
            i += i&-i;
        }
    }
    int Binary_sereach(int i) {//i表示当前还在圈中的第i个人(从0开始编号的),所以可以理解成在这个人之前还有i个人
        int lb = 0, ub = size;
        while (ub - lb > 1) {
            int mid = (ub + lb)>>1;
            if (sum(mid) <= i) {
                lb = mid;
            }
            else
                ub = mid;
        }
        return lb;
    }
};

BItree Bit;

int main() {
    int N, K;
    init_factor_num(N_MAX+4);
    while(scanf("%d%d",&N,&K)!=EOF){
        K--;//编号从0开始
        Bit.init_BIT(N);
        for (int i = 0; i < N; i++) {
            scanf("%s %d", name[i], &number[i]);
            Bit.add(i,1);//!!!
        }
        
        int index, max_num = -1;
        for (int i = 0; i < N; i++) {//模拟,总共循环n次,每次意味着走掉一个小孩
            if (max_num < factor_num[i+1]) {
                max_num = factor_num[i + 1];
                index = K;//记录下标,按初始编号的第K个小孩拿到这么多糖果
            }
            Bit.add(K, -1);//那个位置的小孩走了,人数减1
            //接下来要挑选出下一个要走的小孩的初始编号K
            if (i < N - 1) {//!!!
                int num = N - i - 1;//num是总人数
                int id = Bit.sum(K) + number[K] + (number[K] > 0 ? -1 : 0);//使得id的编号也是从0开始计数的!!!!!!!
                id = (id%num+num)%num;//!!!!!可能id是负数,所以必须mod之后再加上num使得变为正数后再进行mod
                
                K=Bit.Binary_sereach(id);
            }
        }
        printf("%s %d\n",name[index],max_num);
    }
    return 0;
}

 




转载于:https://www.cnblogs.com/ZefengYao/p/6617350.html

你可能感兴趣的:(poj 2886 Who Gets the Most Candies?)