POJ - 2886 Who Gets the Most Candies? (线段树+反素数)

题意:有n个小盆友围成一圈,从第k个小朋友开始,选中谁谁退圈,每个小朋友都有一个数num,这个数为正数表明下一个选中的小朋友即为这个小朋友左边第num个小朋友,为负数表明下一个选中的小朋友为这个小朋友右边第num个小朋友。每个小朋友退圈即可获得p的因子数的糖果数,p为这个小朋友是第几个退圈的,输出这个获得最多的糖果的小朋友的名字和她获得的糖果数。

思路:n个小朋友,获得最多的糖果的那个人的编号为1-n中有最多因子数的那个数,所以就需要求出反素数,以下是关于反素数的相关知识。

反素数的定义:对于任何正整数,其约数个数记为n,例如f(6)=4,如果某个正整数满足:对任意的正整数i(0<i<n)  ,都有f(i)<f(n),那么称为n反素数。

从反素数的定义中可以看出两个性质:

(1)一个反素数的所有质因子必然是从2开始的连续若干个质数,因为反素数是保证约数个数为的这个数尽量小

(2)同样的道理,如果n=2^{t1}\ast 3^{t2}\ast 5^{t3}\ast 7^{t4}\ast,那么必有t1\leq t2\leq t3\leq t4


对于这道题,我们直接按照反素数的定义枚举打表即可了:

#include <stdio.h>
#include <vector>
using namespace std;
const int maxn = 600005;
vector<int> antiprime,factor;
int get(int n)
{
    int res,i,t;
    res = 1;
    for(i = 2; i * i <= n; i++) {
        t = 0;
        while(n % i == 0) {
            t++;
            n /= i;
        }
        res *= (t + 1);
    }
    if(n != 1)
        res *= 2;
    return res;
}
int main(void)
{
    int i,Max,t;
    Max = 0;
    for(i = 1; i < maxn; i++) {
        t = get(i);
        if(t > Max) {
            antiprime.push_back(i);
            factor.push_back(t);
            Max = t;
        }
    }
    return 0;
}

这样我们就找出来了1-n中有最多因子数的那个数q,然后我们找出来第q个出圈的小盆友就行了,如何求就用到了线段树,线段树存储的是区间还剩多少小朋友,知道现在要出圈的小朋友在此时此刻的圈里的位置k,根据他的数可以求出下一个要出圈的小朋友在此时此刻圈里的位置,注意在左边与在右边的求法不一样,在纸上画一画就知道了。然后就可以利用线段树求出这个小朋友在初始圈里的位置,知道这个位置就知道了他的数,这样循环求下去,就得到第q个出圈的小朋友。

#include <stdio.h>
#include <string.h>
#define lson num << 1
#define rson num << 1 | 1
#define maxn 500005
const int antiprime[] = {1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,1260,1680,2520,5040,7560,10080,15120,20160,25200,27720,45360,50400,55440,83160,110880,166320,221760,277200,332640,498960,554400};
const int factor[] = {1,2,3,4,6,8,9,10,12,16,18,20,24,30,32,36,40,48,60,64,72,80,84,90,96,100,108,120,128,144,160,168,180,192,200,216};
struct node
{
    int l,r,sum;
}tree[maxn << 2];
char name[maxn][20];
int val[maxn];
void pushup(int num)
{
    tree[num].sum = tree[lson].sum + tree[rson].sum;
}
void build(int num,int l,int r)
{
    tree[num].l = l;
    tree[num].r = r;
    if(l == r) {
        tree[num].sum = 1;
        return;
    }
    int mid = (l + r) >> 1;
    build(lson,l,mid);
    build(rson,mid + 1,r);
    pushup(num);
}
int update(int k,int num,int l,int r)
{
    if(l == r) {
        tree[num].sum = 0;
        return l;
    }
    int ans,mid;
    mid = (l + r) >> 1;
    if(k <= tree[lson].sum)
        ans = update(k,lson,l,mid);
    else
        ans = update(k - tree[lson].sum,rson,mid + 1,r);
    pushup(num);
    return ans;
}
int main(void)
{
    int i,n,k,cnt,pos;
    while(scanf("%d %d",&n,&k) != EOF) {
        for(i = 1; i <= n; i++)
            scanf("%s %d",name[i],&val[i]);
        cnt = 0;
        while(antiprime[cnt] <= n)
            cnt++;
        cnt--;
        build(1,1,n);
        for(i = 0; i < antiprime[cnt]; i++) {
            pos = update(k,1,1,n);
            if(i == antiprime[cnt] - 1) break;
            if(val[pos] > 0)
                k = ((k - 1 + val[pos] - 1) % tree[1].sum + tree[1].sum) % tree[1].sum + 1;
            else
                k = ((k + val[pos] - 1) % tree[1].sum + tree[1].sum) % tree[1].sum + 1;
        }
        printf("%s %d\n",name[pos],factor[cnt]);
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章