poj 2886 Who Gets the Most Candies?(线段树#3)

因为孩子们总要跳出圈子,所以计算出的要删除的索引应该是相对目前的孩子总数而言的,这里用Delete函数删除并返回删除的那个孩子的初始标号。

还有关于一个整数的约数的个数的的问题,这里我采用了打表的方法。1750ms


#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring> 
using namespace std;
#define N 500005 

int candysum[N]; 
struct node{
       int l, r, num;
}Tree[N * 5];
int a[N];
char name[N][15]; 

 
void init() 
{
     memset(candysum, 0, sizeof(candysum));
     for (int i = 1; i < N; i++)
     {
          ++candysum[i];
          for(int j = i * 2; j < N; j += i)
              ++candysum[j];
     } 
}

void build(int l, int r, int x)
{
     Tree[x].l = l;
     Tree[x].r = r;
     Tree[x].num = (r - l + 1); 
     if (l  ==  r)return;
     int mid = (l + r) / 2;
     build(l, mid, x * 2);
     build(mid + 1, r, x * 2 + 1);
} 

int Delete(int tag, int x)
{
      --Tree[x].num; 
      if (Tree[x].l == Tree[x].r)
      {
             return Tree[x].l;
      }
      int ans;  
      if (Tree[x * 2].num >= tag)
            ans =  Delete(tag, x * 2);
      else 
            ans = Delete(tag - Tree[x * 2].num, x * 2 + 1);
      return ans; 
}   
    
     
int main()
{
      int n, k;
      init();
    //  FILE* fp = fopen("in.txt", "r"); 
      while (scanf( "%d", &n) != EOF)
      {
            scanf( "%d", &k);
            int ans = 1;
            int tmp = 1; 
            for (int i = 2; i <= n; i++)
            {
                  if (candysum[i] > candysum[ans])
                              ans = i;
            } 
            build(1, n, 1);
            for (int i = 1; i <= n; i++)
                scanf( "%s %d", name[i], a + i);
            int sum = n;
            for (int i = 1; i < ans; i++)
            {
                    int cur = Delete(k, 1);
                    int m = a[cur]; 
                    sum--; 
                    if (m > 0)
                    {
                           m--; 
                           k = (k - 1 + sum + m)%sum + 1;
                    } 
                    else   k = (k - 1  + sum -  (-m % sum) )% sum + 1;
            }
            printf("%s %d\n", name[Delete(k, 1)], candysum[ans]); 
          //   getchar(); 
      } 
    //   getchar();          
      
      return 0;
} 


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值