Who Gets the Most Candies? POJ - 2886(反素数打表+线段树+约瑟夫环)

关于反素数的问题就不在说名,可以自己找题目去做

这里讲一下自己对约瑟夫环问题的理解,如果有错希望有人指明,,因为看了很多博客都没怎么看懂,

自己想了一下:这个问题线段树能处理的剩余空余的位置中的第几个位置,比如第一个2走了之后剩余3个人线段树可以找出剩余3人中的第几个,现在的问题就是怎么将剩余的几个人的第几个找出来,

打表代码

#include <iostream>

using namespace std;


int tt;
int ans,anum;
int p[16] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
int a[111];
int b[111];
int cont=0;
void dfs(int d,int t,int num)
{
    if(d>7) return;
    if(anum<num)
    {
        anum=num;
        ans=t;
    }
    else if(anum==num)
    {
        if(t<ans)
            ans=t;
    }
    for(int i=1;i<=64;i++)
    {
        if(t*p[d]>tt) break;
        t*=p[d];
        dfs(d+1,t,num*(i+1));
    }
}
int main()
{
    tt=1;
    a[cont]=1;
    b[cont++]=1;
    for(int i=2;i<555555;i++)
    {
        tt=i;
        ans=555555;
        anum=0;
        dfs(0,1,1);
        if(anum>b[cont-1])
        {
            a[cont]=ans;
            b[cont++]=anum;
        }
        else if(anum==b[cont-1])
        {
            if(a[cont-1]<ans)
                a[cont-1]=ans;
        }
    }
    cout<<cont<<endl;
    for(int i=0;i<cont;i++)
        printf("%d,",a[i]);
    printf("\n");
    for(int i=0;i<cont;i++)
        printf("%d,",b[i]);
    return 0;
}
36
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,
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,
#include <iostream>
#include <cstring>
#include <string>


using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define MAXN 555555

int stree[MAXN<<2];
int a[]={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};
int b[]={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
{
    char name[111];
    int num;    
}stu[MAXN];
void pushup(int rt)
{
    stree[rt]=stree[rt<<1]+stree[rt<<1|1];
}
void build(int l,int r,int rt)
{
    if(l==r)
    {
        stree[rt]=1;
        return;
    }
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
int tt;
void update(int k,int l,int r,int rt)
{
    if(l==r)
    {
        stree[rt]=0;
        tt=l;
        return;
    }
    int mid=(l+r)>>1;
    if(k<=stree[rt<<1]) update(k,lson);
    else update(k-stree[rt<<1],rson);
    pushup(rt);
}
int main()
{
    int n,k;
    while(scanf("%d%d",&n,&k)==2)
    {
        build(1,n,1);
        for(int i=1;i<=n;i++)
            scanf("%s%d",stu[i].name,&stu[i].num);
        int cont=0;
        while(a[cont]<=n)
            cont++;
        cont--;
        int cont1=0;
        while(1)
        {
            update(k,1,n,1);
            cont1++;
            if(cont1==a[cont]) break;
            if(stu[tt].num>0)
                k=(k-1+stu[tt].num-1)%stree[1]+1;
            else 
                k=((k+stu[tt].num-1)%stree[1]+stree[1])%stree[1]+1;
        }
        printf("%s %d\n",stu[tt].name,b[cont]);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值