poj 2886 Who Gets the Most Candies?

简介: 点击打开poj 2886 思路: 求因子数+单点更新 分析: 1 题目的意思是有n个人构成一个环,刚开始是第k个人先出来。每个人有一个名字和数值A,如果A为正数,那么下一个出去的人是他左边的第A个人,如果是负数那么出去的将是右边的第A个人 2 这么我们要注意一下,因为n个人是围城一圈,那么左边就是顺时针方向,右边就是逆时针方向 3 那么我们就可以来推没一次出去的人的在剩下中是第几个。

点击打开poj 2886

思路: 求因子数+单点更新

分析:

1 题目的意思是有n个人构成一个环,刚开始是第k个人先出来。每个人有一个名字和数值A,如果A为正数,那么下一个出去的人是他左边的第A个人,如果是负数那么出去的将是右边的第A个人


2 这么我们要注意一下,因为n个人是围城一圈,那么左边就是顺时针方向,右边就是逆时针方向


3 那么我们就可以来推没一次出去的人的在剩下中是第几个。

   假设当前是第k个人出去,并且这个人的值为A,并且剩下有sum个人


   A > 0 , 因为这个人出去了,那么后面的人的编号会先减一,那么下一个出去的人就是剩下中的 (k+A-1)%sum,因为我们知道%sum的结果是0~sum-1,但是我们要得到1~sum的结果,因此我们可以这样 ((k+A-1)%sum-1+sum)%sum+1。怎么理解呢,比如x%3,那么结果就是0~2,为了得到结果为1~3,那么我们可以这样(x-1+3)%3+1,括号里面加3怕负数的情况


   A < 0 , 因为这个人出去,对前面的人是没有影响的,因此编号就是 ((k+A)%sum+sum-1+sum)%sum+1,根据上面的解释以及怕出现负数的情况,我们多加了sum来抵消


4 我们现在求出了每一次出去的人是剩下人中的第几个,但是我们怎么去求出具体的是哪一个人呢?

    这个时候我们就可以利用线段树来维护,线段树的区间维护的是当前这个区间还有多少个孩子,那么我们只要查找前面求出的第几个孩子就可以得到编号


代码:

/************************************************
 * By: chenguolin                               * 
 * Date: 2013-09-13                             *
 * Address: http://blog.csdn.net/chenguolinblog *
 ************************************************/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

#define lson(x) (x<<1)
#define rson(x) (x<<1|1)
#define mid(x,y) (x+y)>>1

const int N = 11;
const int MAXN = 500010;

int num[MAXN];
int n , k;

struct Person{
    char name[N];
    int val;
};
Person p[MAXN];

struct Node{
    int left;
    int right;
    int sum;
};
Node node[4*MAXN];

// 打出所有的数的因子的个数
void init(){
    int t = sqrt(MAXN);
    for(int i = 1 ; i <= t ; i++){
        num[i] = 1;
        for(int j = 1 ; j <= sqrt(i) ; j++)
            if(i%j == 0)
                num[i]++;
        if(i > 1) num[i*i] = num[i]+1;
    }
    /*
    int i , j , limit;  
    limit = (int)sqrt(MAXN*1.0);  
    for(i = 1 ; i <= limit ; i++){  
        for(j = i+1 ; j*i < MAXN ; j++)  
            num[i*j] += 2;  
        num[i*i]++;  
    }
    */
}

void push_up(int pos){
    node[pos].sum = node[lson(pos)].sum+node[rson(pos)].sum;
}

void buildTree(int left , int right , int pos){
    node[pos].left = left;
    node[pos].right = right;
    node[pos].sum = right-left+1;
    if(left == right)
        return;
    int mid = mid(left , right);
    buildTree(left , mid , lson(pos));
    buildTree(mid+1 , right , rson(pos));
}

void update(int id , int pos){
    if(node[pos].left == node[pos].right){
        node[pos].sum--;
        return;
    }
    int mid = mid(node[pos].left , node[pos].right);
    if(id <= mid)
        update(id , lson(pos));
    else
        update(id , rson(pos));
    push_up(pos);
}

int query(int x , int pos){
    if(node[pos].left == node[pos].right)
        return node[pos].left;
    if(node[lson(pos)].sum >= x)
        return query(x , lson(pos));
    else
        return query(x-node[lson(pos)].sum , rson(pos));
}


void solve(){
    buildTree(1 , n , 1);
    int ans = 0;
    int nameId;
    int id = k;
    for(int i = 1 ; i <= n ; i++){
        update(id , 1);
        int sum = node[1].sum;
        if(ans < num[i]){
            ans = num[i];
            nameId = id;
        }
        if(sum){
           int A = p[id].val;
           if(A > 0)
               k = ((k+A-1)%sum-1+sum)%sum+1;
           else
               k = ((k+A)%sum+sum-1+sum)%sum+1;
        }
        id = query(k , 1);
    }
    printf("%s %d\n" , p[nameId].name , ans);
}

int main(){
    init();
    while(scanf("%d%d" , &n , &k) != EOF){
        for(int i = 1 ; i <= n ; i++)
            scanf("%s%d" , p[i].name , &p[i].val);
        solve();
    }
    return 0;
}



目录
相关文章
poj 3298 数状数组
题目大意是一条大街上住着n个乒乓球爱好者,他们的水平高低用一个数值表示,他们经常举办比赛,比赛要三个人,一人当裁判。对裁判是有一定要求的,裁判的水平必须介于两选手之间且必须住他们中间,计算可以举办多少场比赛
41 0
POJ 1067 取石子游戏
取石子游戏 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 40917   Accepted: 13826 Description 有两堆石子,数量任意,可以不同。
1112 0
|
测试技术
POJ 1001
此题用最朴素的思路实现即可,需模拟加法器,乘法器,最烦人的地方是特殊情形,如末位是小数点(12.^2=144,取小数点),整数末位是0(100^2=10000),0次幂,测试用例可能超出题目中说的范围,可能包含0次幂(100.0^0=0, 0.10^1=0.1)。
752 0
|
人工智能
POJ 2531
初学dfs参考别人代码,如有雷同,见怪不怪。#include using namespace std; int aa[25][25]; int maxa=0; int step[25]={0},n; void dfs(int a,int b) { int t=b; step...
709 0
poj 1455
Description n participants of > sit around the table. Each minute one pair of neighbors can change their places.
618 0
poj-1008-玛雅历
Description 上周末,M.A. Ya教授对古老的玛雅有了一个重大发现。从一个古老的节绳(玛雅人用于记事的工具)中,教授发现玛雅人使用了一个一年有365天的叫做Haab的历法。这个Haab历法拥有19个月,在开始的18个月,一个月有20天,月份的名字分别是pop, no, zip, zotz, tzec, xul, yoxkin, mol, chen, yax, zac, ceh, mac, kankin, muan, pax, koyab, cumhu。
883 0
|
算法 数据建模 机器学习/深度学习
poj1273Drainage Ditches
1 #include 2 /* 3 题意:就是寻找从源点到汇点的最大流! 4 要注意的是每两个点的流量可能有多个,也就是说有重边,所以要把两个点的所有的流量都加起来 5 就是这两个点之间的流量了! 6 ...
851 0
|
机器学习/深度学习 Windows
|
算法 计算机视觉
最小割-poj-2914
poj-2914-Minimum Cut Description Given an undirected graph, in which two vertices can be connected by multiple edges, what is the size of the minimum cut of the graph? i.e. how many edges must b
1561 0