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
    评论
这是一道比较经典的计数问题。题目描述如下: 给定一个 $n \times n$ 的网格图,其中一些格子被标记为障碍。一个连通块是指一些被标记为障碍的格子的集合,满足这些格子在网格图中连通。一个格子是连通的当且仅当它与另一个被标记为障碍的格子在网格图中有公共边。 现在,你需要计算在这个网格图中,有多少个不同的连通块,满足这个连通块的大小(即包含的格子数)恰好为 $k$。 这是一道比较经典的计数问题,一般可以通过计算生成函数的方法来解决。具体来说,我们可以定义一个生成函数 $F(x)$,其中 $[x^k]F(x)$ 表示大小为 $k$ 的连通块的个数。那么,我们可以考虑如何计算这个生成函数。 对于一个大小为 $k$ 的连通块,我们可以考虑它的形状。具体来说,我们可以考虑以该连通块的最左边、最上边的格子为起点,从上到下、从左到右遍历该连通块,把每个格子在该连通块中的相对位置记录下来。由于该连通块的大小为 $k$,因此这些相对位置一定是 $(x,y) \in [0,n-1]^2$ 中的 $k$ 个不同点。 现在,我们需要考虑如何计算这些点对应的连通块是否合法。具体来说,我们可以考虑从左到右、从上到下依次处理这些点,对于每个点 $(x,y)$,我们需要考虑它是否能够与左边的点和上边的点连通。具体来说,如果 $(x-1,y)$ 和 $(x,y)$ 都在该连通块中且它们在网格图中有公共边,那么它们就是连通的;同样,如果 $(x,y-1)$ 和 $(x,y)$ 都在该连通块中且它们在网格图中有公共边,那么它们也是连通的。如果 $(x,y)$ 与左边和上边的点都不连通,那么说明这个点不属于该连通块。 考虑到每个点最多只有两个方向需要检查,因此时间复杂度为 $O(n^2 k)$。不过,我们可以使用类似于矩阵乘法的思想,将这个过程优化到 $O(k^3)$ 的时间复杂度。 具体来说,我们可以设 $f_{i,j,k}$ 表示状态 $(i,j)$ 所代表的点在连通块中,且连通块的大小为 $k$ 的方案数。显然,对于一个合法的 $(i,j,k)$,我们可以考虑 $(i-1,j,k-1)$ 和 $(i,j-1,k-1)$ 这两个状态,然后把点 $(i,j)$ 加入到它们所代表的连通块中。因此,我们可以设计一个 $O(k^3)$ 的 DP 状态转移,计算 $f_{i,j,k}$。 具体来说,我们可以考虑枚举连通块所包含的最右边和最下边的格子的坐标 $(x,y)$,然后计算 $f_{x,y,k}$。对于一个合法的 $(x,y,k)$,我们可以考虑将 $(x,y)$ 所代表的点加入到 $(x-1,y,k-1)$ 和 $(x,y-1,k-1)$ 所代表的连通块中。不过,这里需要注意一个细节:如果 $(x-1,y)$ 和 $(x,y)$ 在网格图中没有相邻边,那么它们不能算作连通的。因此,我们需要特判这个情况。 最终,$f_{n,n,k}$ 就是大小为 $k$ 的连通块的个数,时间复杂度为 $O(n^2 k + k^3)$。 参考代码:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值