• POJ 2886 Who Gets the Most Candies? (线段树)题解


    题意:一堆小朋友围成一个圈,规定从k开始玩,每个被选中的人都有一个数字,正数代表从他左边开始数num,负数从右边数,被选中的人继续按照上述操作,直到都退出圈子,第i个退圈的人能拿到一个点数,这个点数是i的因数个数(比如第4个人拿3点)。问:谁点数最多,一样多选第一个。

    思路:一道好题啊,万万没想到是线段树,想要想到感觉还是有点难度的。这道题其实就是要一直维护剩余人数,但是以前没做过线段树维护剩余人数的,一时半会想不到...首先,我们要用打表找到所有点数。然后用线段树维护剩余人数,这里有一个剩余人数位置和所有人数位置转换的过程,是用线段树解决的。线段树的每个节点储存的是某个区间的剩余人数,所以我们在用一个人在剩余人中的位置找到他的编号时,是比较sum节点而非L,R。还有向左向右方向要注意,画个圈慢慢感受。具体看注释。

    代码:

    #include<cstdio>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<cstdlib>
    #include<algorithm>
    #define ll long long
    const int maxn = 500000+5;
    const int MOD = 1e7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    struct node{
        char name[12];
        int num;
    }e[maxn];
    int get[maxn],sum[maxn << 2];
    void pushup(int rt){
        sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
    }
    void build(int l,int  r,int rt){
        if(l == r){
            sum[rt] = 1;
            return;
        }
        int m = (l + r) >> 1;
        build(l,m,rt << 1);
        build(m + 1,r,rt << 1 | 1);
        pushup(rt);
    }
    int update(int pos,int l,int r,int rt){
        if(l == r){
            sum[rt] = 0;
            return l;
        }
        int ans;
        int m = (l + r) >> 1;
        if(pos <= sum[rt << 1]) //pos代表在剩余人数中的第几个,所以写法略有不同
            ans = update(pos,l,m,rt << 1);
        else
            ans = update(pos - sum[rt << 1],m + 1,r,rt << 1 | 1);
        pushup(rt);
        return ans;
    }
    void init(){
        int top = 500000;
        memset(get,0,sizeof(get));
        for(int i = 1;i <= top;i++){
            get[i]++;
            for(int j = 2*i;j <= top;j += i){
                get[j]++;
            }
        }
    }
    int main(){
        init();
        int n,k;
        while(~scanf("%d%d",&n,&k)){
            build(1,n,1);
            for(int i = 1;i <= n;i++)
                scanf("%s%d",e[i].name,&e[i].num);
            int aim = 0,MAX = -1;
            for(int i = 1;i <= n;i++){
                if(get[i] > MAX){
                    aim = i;
                    MAX = get[i];
                }
            }
            int pos;    //开始计算的位置
            int mov,all,now = 0;
            while(true){
                pos = update(k,1,n,1);    //被宰的是哪个人
                now++;
                if(now == aim) break;
                mov = e[pos].num;
                if(mov > 0){    //在左边
                    k = (k - 1 + mov - 1)%sum[1] + 1;   //这里的pos是剩余人中的编号
                    //第一个-1是因为pos这个人已经被宰了,所以他这个位置其实是没有的
                    //第二个-1是防止%之后归0,所以先-1再+1
                }
                else{   //在右边
                    k = ((k - 1 + mov)%sum[1] + sum[1])%sum[1] + 1;
                }
            }
            printf("%s %d
    ",e[pos].name,MAX);
        }
        return 0;
    }
    
  • 相关阅读:
    POJ 1703 Find them, Catch them
    POJ 2236 Wireless Network
    POJ 2010 Moo University
    POJ 2184 Cow Exhibition
    POJ 3280 Cheapest Palindrome
    POJ 3009 Curling 2.0
    POJ 3669 Meteor Shower
    POJ 2718 Smallest Difference
    POJ 3187 Backward Digit Sums
    POJ 3050 Hopscotch
  • 原文地址:https://www.cnblogs.com/KirinSB/p/9408753.html
Copyright © 2020-2023  润新知