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;
}

 

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