poj 2886 Who Gets the Most Candies?

点击打开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;
}
时间: 2024-11-03 15:12:13

poj 2886 Who Gets the Most Candies?的相关文章

POJ 2886 单点更新

题意:n个小孩围一圈,他们手上卡片的数字代表下一个要出去的孩子,第K个孩子出去得到糖的数量是k的约数,输出得到糖最多的那个孩子的姓名和糖数. 首先要求反素数,也就是约数最多的,打表就行.然后线段树节点存放这个区间有多少个孩子还没走.然后模拟这个过程求出第P个孩子. #include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #d

数据结构专题

打星号的表示个人认为比较经典,或是算法比较好的题目   1195 Mobile phones 树状数组 1455 1521 Entropy huffman 1703 Find them, Catch them 并查集 1785 Binary Search Heap Construction 1794 Castle Walls 逆序对 1961 Period KMP重复因子 1984* Navigation Nightmare 并查集+坐标平移 1986* Distance Queries LCA

POJ 最短路问题题号汇总

求最短路基本的算法: 1>Dijkstra算法2>Bellman-Ford算法3>Floyd算法4>Floyd-Warshall算法5>Johnson算法6>A*算法 题目: 1.poj1062 昂贵的聘礼(中等)     此题是个经典题目:用Dijkstra即可:但是其中的等级处理需要一定的技巧:    要理解好那个等级制度:这个处理好,基本就是裸体Dijkstra: 2 poj1125 Stockbroker Grapevine(基本)    这个是简单Floyd,

POJ题目分类

初期: 一.基本算法:      (1)枚举. (poj1753,poj2965)      (2)贪心(poj1328,poj2109,poj2586)      (3)递归和分治法.      (4)递推.      (5)构造法.(poj3295)      (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996) 二.图算法:      (1)图的深度优先遍历和广度优先遍历.      (2)最短路径算法(dijkstra,bellman-ford

POJ:DNA Sorting 特殊的排序

Description One measure of ``unsortedness'' in a sequence is the number of pairs of entries that are out of order with respect to each other. For instance, in the letter sequence ``DAABEC'', this measure is 5, since D is greater than four letters to

POJ 1001 Exponentiation 无限大数的指数乘法 题解

POJ做的很好,本题就是要求一个无限位大的指数乘法结果. 要求基础:无限大数位相乘 额外要求:处理特殊情况的能力 -- 关键是考这个能力了. 所以本题的用例特别重要,再聪明的人也会疏忽某些用例的. 本题对程序健壮性的考查到达了变态级别了. 更多精彩内容:http://www.bianceng.cnhttp://www.bianceng.cn/Programming/sjjg/ 某人贴出的测试用例数据地址: http://poj.org/showmessage?message_id=76017 有

POJ 2240 Arbitrage:最短路 Floyd

Arbitrage:http://poj.org/problem?id=2240 大意: 给你m种货币,给你m种货币兑换规则,问通过这些规则最后能不能盈利.eg:1美元换0.5英镑,1英镑换10法郎,1法郎换0.21美元,这样1美元能换0.5*10*0.21=1.05美元,净赚0.05美元. 思路: 用Floyd找出每两种钱之间的最大兑换关系,遍历一遍,看有没有那种钱币最后能盈利,有就输出Yes,没有就是No.在处理钱币名称与编号之间的关系时,可以用map存(比较好用),当然也可以用字符串比较.

POJ 1860 Currency Exchange:最短路 Bellman-Ford

Currency Exchange:http://poj.org/problem?id=1860 大意:有多种货币,之间可以交换,但是需要手续费,也就是说既有汇率又有手续费.问经过交换之后能不能赚. 思路:Bellman_Ford,因为要求最长路,所以松弛条件改一下就好了. Tips: 3              2                  1                20.0货币的数量   兑换点的数量     主人公拥有的货币量    主人公拥有货币的价值1 2 1.00

POJ 1258 Agri-Net:最小生成树 Prim 模版题

Agri-Net:http://poj.org/problem?id=1258 大意:新镇长竞选宣言就是将网络带到每一个农场,给出农场个数,两两之间建光缆的耗费,求所有都联通的最小耗费. 思路:最小生成树,因为边比较稠密,用Prim做. PS:对于比较稠密的图,用Prim,对于比较稀疏的图,用 Kruskal.Kruskal是找边的过程,稀疏的话会比较快. 更多精彩内容:http://www.bianceng.cnhttp://www.bianceng.cn/Programming/sjjg/