poj 2886 Who Gets the Most Candies?*

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

Description

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

N个小孩子坐成一圈玩游戏

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.

小孩用数字1到N来标示,以顺时针的顺序。每个人有一个卡片,上面写着一个非零的数字。游戏从第k个孩子开始,那个人念出自己的卡片数字后离开圈圈。他念的数字标示下一个跳出圈圈的孩子是谁。A表示那个数字。如果A是正数,下个孩子就是左面的第A个孩子,如果A是负数,下个孩子就是右边第(-A)个孩子

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?

游戏在所有孩子都离开圈圈后结束。游戏进行中,第p个孩子离开圈圈将会得到F(p)个蜡烛,F(p)是p的约数的个数

Input

There are several test cases in the input. Each test case starts with two integers  N (0 <  N  ≤ 500,000) and K (1 ≤ K ≤ N) on the first line. The next Nlines 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.
输入有多组数据。每组数据开始有两个整数 N  (0 <  N   ≤ 500,000) 和 K (1 ≤ K ≤ N)在第一行。接下来N行包括孩子的名字(最大包括十个字母)和卡片上的数字(正整数小于108)以一个递增的顺序,姓名和数字用一个空格隔开,开头结尾没空格。

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

Source


有个反素数的概念,就是比他小 的数的约数都比他小。。。然后,这个概念俺也没用上,就是他们都在说,我觉得还是放在这里吧。
这里就是直接求了一下约数个数,用的深搜,方法也是跟别人学的,有一个数学公式,就是一个数的约数个数就是分解质因数后的那些质因数的指数+1的乘积,用文字叙述太累了。。。还看不懂,上公式。。。
设此数是N
分解质因数
N=p1^a1*p2^a2*……*pn^an
则约数的个数是(a1+1)*(a2+1)*……*(an+1)

然后就是怎么往队伍外面撵人了。。。基本上只需要考虑撵到求因数个数最大的那个人。因为之后的人撵了也不会拿到更多蜡烛了。。。

之后就是神奇的线段树。。。基本建树和更新节点的值都很简单,主要就是那个相对位置的转换,其实我到现在也没弄太明白。。。先打个**做个备注吧。。。现在知道的是:当数为正的时候,由于自己已经被撵出去了,所以得-1。数为负的时候,由于跟自己也无关,所以不用-1,至于后面那多-的一个1,还有一堆取模运算,大概是因为取模是能取到0的。。。这里是把0那种情况给剔除了,毕竟线段树是从1-n的。。。不过到底是咋剔除的嘞。。。数学不好,待我学习一下。。。

#include <stdio.h>
#include <string.h>
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1

const int maxn = 555555;
int sumtree[maxn << 2];
char name[maxn][12];
int card[maxn];
int n, k, ans = 0, sumbest = 0;
int prime[16] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47};

void dfs(int num, int sum, int count, int pr){
    int i, p;
    if (num > n){
        return;
    }
    if (sum == sumbest && num < ans){
        ans = num;
    }else if (sum > sumbest){
        sumbest = sum;
        ans = num;
    }
    p = prime[pr];
    for (i = 1;i <= count ;i ++){
        if ((num * p) > n)
            break;
        dfs(num * p, sum*(i + 1), i, pr + 1);
        p *= prime[pr];
    }
    return;
}

void build(int l, int r, int rt){
    int m;
    sumtree[rt] = r - l + 1;
    if (l == r)
        return;

    m = (l + r) >> 1;
    build(lson);
    build(rson);
    return;
}

int updata(int a, int l, int r, int rt){
    int ret, m;
    sumtree[rt] --;
    if (l == r)
        return l;
   
    m = (l + r) >> 1;
    ret = 0;
    if (sumtree[rt << 1] >= a){
        ret = updata(a, lson);
    }else{
        a -= sumtree[rt << 1];
        ret = updata(a, rson);
    }
    return ret;
}

int main(void){

    freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    int i;
    int pos = 0;
    
    while(scanf("%d%d", &n, &k) != EOF){
        sumbest = 0;ans = 0;
        dfs(1, 1, 50, 0);
        build(1, n, 1);

        for (i = 1;i <= n;i ++){
            scanf("%s %d", name[i], &card[i]);
        }
        pos = 0;
        for (i = 0;i < ans;i ++){
            if (i != 0)
                if (card[pos] > 0){
                    printf("> 0 k = %d, card[%d] = %d, sumtree[1] = %d\n", k, pos, card[pos], sumtree[1]);
                    k = (((k + card[pos] - 2) % sumtree[1] + sumtree[1]) % sumtree[1]) + 1 ;
                    printf("##> 0 k = %d, card[%d] = %d, sumtree[1] = %d\n", k, pos, card[pos], sumtree[1]);
                }
                else{ 
                    //k = (k + card[pos]) % sumtree[1];
                    k = (((k + card[pos] - 1) % sumtree[1] + sumtree[1]) % sumtree[1]) + 1 ;
                    printf("< 0 k = %d \n", k);
                }
            pos = updata(k, 1, n, 1);
            printf("pos = %d \n", pos);
        }
        printf("%s %d\n", name[pos], sumbest);
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值