zoukankan      html  css  js  c++  java
  • POJ2886Who Gets the Most Candies?(线段树之约瑟夫)

    约瑟夫问题的升级版,每次出去的是前一个出去的人位置+手上的数字(正往前,负往后)。第i个出去的人拿的糖是i的约数的个数。求拿糖最多的人和他的糖果数。

    这里用到了反素数的知识,在这直接打表

    题目

    AC代码:

    #include<stdio.h>
    #include<string.h>
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    
    const int N = 500002;
    int v[N],sum[N<<2],n,k;
    char name[N][11];
    int rprim[50]= {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 nprim[50]= {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};///反素数的约数个数
    void build(int l,int r,int rt)
    {
        sum[rt]=r-l+1;///sum储存这个区间有多少的数
        if(l<r)
        {
            int m=(l+r)>>1;
            build(lson);
            build(rson);
        }
    }
    int update(int l,int r,int rt,int k)
    {
        sum[rt]--;///这个区间减少一个数
        if(l==r)
            return l;///返回这个减少的数的原始下标
            int m=(l+r)>>1;
        if(k<=sum[rt<<1])///要找的第k个数小于等于左半区间的个数
            return update(lson,k);///就递归左子树
        else
            return update(rson,k-sum[rt<<1]);///否则就在右子树,且k-左子树的个数
    }
    int main( )
    {
        while(scanf("%d%d",&n,&k)!=EOF)
        {
            memset(name,0,sizeof(name));
            for(int i=1 ; i<=n ;i++)
                scanf("%s%d",name[i],&v[i]);
            build(1,n,1);
            int tn=n,now,p=0;
            while(rprim[p]<=n)///找出n里最大的反素数
                p++;
            for(int i=1 ; i<rprim[p-1] ; i++)///反素数前的都出队
            {
                now=update(1,n,1,k);///当前出队的序号
                tn--;///剩下的人数
                if(v[now]>0)///向前数
                    k=(k-1+v[now])%tn;///先减去本身这个位置 然后往前v个 再取模
                else
                    k=((k+v[now])%tn+tn)%tn;///直接往后 然后要取模再取模保证正数
                if(k==0)///如果刚好是tn 取模会变成0
                    k=tn;
            }
            now=update(1,n,1,k);///得到第最大的反素数个出队的人的序号
            printf("%s %d
    ",name[now],nprim[p-1]);
        }
        return 0;
    }
    View Code

    不懂反素数的可以点击此链接:反素数

  • 相关阅读:
    MAC 使用git时 不自动补全
    MAC 下 安装redis 并配置 php redis 扩展
    PHP日志 LOG4PHP 的配置与使用
    PHP数组 转 对象/对象 转 数组
    将数组打印到txt文件中
    Yii2控制器 返回 json 格式数据
    控制流输出26大小写英文字母
    员工领导部门关系类
    重写父类
    递归(recursion)
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/9083738.html
Copyright © 2011-2022 走看看