POJ 2886 反素数+线段树

题意:

N个人进行约瑟夫环游戏第i轮的人能获得p(i)个糖果求获得最多糖果的人和糖果数

p(i)为数i的因子的个数

分析:

约瑟夫环可以用线段树模拟下一次出局的人(因为每一次出局一个人所有的人的下标都回改变)

知识点:反素数对于任何正整数x,其约数的个数记做g(x).例如g(1)=1,g(6)=4.如果某个正整数x满足:对于任意i(0<i<x),都有g(i)<g(x),则称x为反素数·

因为我们要求的是最大的p(i)1<=i<=n显然答案为最大的比n小的反素数对于的约数打表就可以

ACcode:

#include <iostream>
#include <cstdio>
using namespace std;
#define maxn 500010
#define mid ((l+r)>>1)
#define tmp (st<<1)
#define lson l,mid,tmp
#define rson mid+1,r,tmp|1
int sum[maxn<<2];
#define mod sum[1]
struct N{
    char s[100];
    int num;
    void in(){
        scanf("%s%d",s,&num);
    }
}my[maxn];
void build(int l,int r,int st){
    sum[st]=r-l+1;
    if(l==r)return ;
    build(lson);
    build(rson);
}
int update(int c,int l,int r,int st){
    sum[st]--;
    if(l==r)return r;
    if(c<=sum[tmp])return update(c,lson);
    return update(c-sum[tmp],rson);
}
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};

int factorNum[]={
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};
int main(){
    int n,k;
    while(scanf("%d%d",&n,&k)!=EOF){
        build(1,n,1);
        for(int i=1;i<=n;++i)my[i].in();
        int ans=0;
        while(ans<35&&antiprime[ans]<=n)ans++;
        ans--;
        int pos=0;
        my[pos].num=0;
        for(int i=0;i<antiprime[ans];i++){
            if(my[pos].num>0)
                k=((k-1+my[pos].num-1)%mod+mod)%mod+1;
            else
                k=((k-1+my[pos].num)%mod+mod)%mod+1;
            pos=update(k,1,n,1);
        }
        printf("%s %d\n",my[pos].s,factorNum[ans]);
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值