poj 2886 Who Gets the Most Candies?

题意:模拟约瑟夫环。有N(1<=N<=500000)个孩子,从第K(1<=K<=N)个开始。接下来N行中,每行有这个孩子的名字和数字pos(绝对值小于10^8,表示接下来第N个孩子出局),第P个出局的孩子会得到F(P)的糖果的数目。F(P)定义为:P的因子的数目。

这题我们用线段树来模拟约瑟夫循环:

这题的关键是两个公式,如果从当前的k位置和pos推出下一个孩子的k(其中k表示在当前状态下第几个,pos表示在数组中的下标。)

如果num>0。k=(k-1+node[pos].num)%n+1。。但是之前这个位置的那个人已经被删除,现在的k-1表示是的原来的那个孩子的下一个孩子,所以不能直接加上pos,得减一去修正。最后再加上1得到在当前状态下是第几个。

例如:

1,2,3,4,5,。。。k, k+1,....n;

1 , 2,3,4,5,...............k,k+1...n-1;原来的k+1变成了k;对后面的造成了影响,因此要减1;

如果num<0。k=((k+node[pos].num)%num+n)%n+1。把k减一得到对应的数组下标。虽然之前这个位置的人已经被删除。现在k之前的孩子是不变的,所以不用减一去修正。

 

1,2,3,4,5,。。。k, k+1,....n;

 

1 , 2,3,4,5,...............k,k+1...n-1;对K以前的排序没影响,因此不变;

 

View Code
#include<iostream>

#include<cstdio>

#include<cstdlib>

#include<algorithm>

#include<cmath>

#include<queue>

#include<set>

#include<map>

#include<cstring>

#include<vector>

#include<string>

#define LL long long

using namespace std;

const int MAX = 500024;

class Node

{

public:

      int l,r,sum;    

}node[MAX*4];

class Message

{

public:

      int num;

      char name[12];    

}peo[MAX];

int candy[MAX],ans;

void Get_candy(  )

{

    memset( candy , 0 , sizeof( candy ) );

    for( int i = 1 ; i < MAX ; i ++ )

    {

         candy[i] ++;

         for( int j = 2*i ; j < MAX ; j += i )

              candy[j] ++;    

    }    

}

void build_tree( int l , int r , int cnt )

{

     node[cnt].l = l;

     node[cnt].r = r;

     node[cnt].sum = r - l + 1;

     if( l == r )  return ;

     int mid = ( l + r ) >>1;

     build_tree( l , mid , cnt*2 );

     build_tree( mid + 1 , r , cnt*2+1 );    

}

void delete_peo( int place ,int c , int &k , int p ,int cnt ,int n )

{

    node[cnt].sum --;

    if( node[cnt].l == node[cnt].r )

    {

        if( p == c )

        {

           ans = node[cnt].l;

           return ;

        }

        if( peo[node[cnt].l].num > 0 )    

            k --;

        k = (( k + peo[node[cnt].l].num )%(n-c) + (n - c) )%( n-c );

        if( k ==0 ) k = n - c;

        return ;

    }

    if( node[cnt*2].sum >= place )

        delete_peo( place , c , k , p , cnt*2 , n );

    else 

    {

       place -= node[cnt*2].sum;

       delete_peo( place , c , k , p  ,cnt*2 + 1 , n );    

    }

}

int main(  )

{

    int n,k;

    Get_candy( );

    while( scanf( "%d %d",&n ,&k )==2 )

    {

         int p = 0;

         for( int i = 1 ; i <= n ; i ++ )

         {

              getchar();

              scanf( "%s %d",peo[i].name , &peo[i].num );

              if( candy[p] < candy[i] )    p = i;    

         }

         ans = 1;

         build_tree( 1 , n , 1 );

         for( int i = 1 ; i <= p ; i ++ )

         {

             delete_peo( k , i , k , p , 1 ,n );        

         }    

         printf( "%s %d\n",peo[ans].name , candy[p] );

    }

    //system( "pause" );

    return 0;

}

 

 

 

 

 

你可能感兴趣的:(get)