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;
}

 

 

 

 

 

posted @ 2012-07-24 11:51  wutaoKeen  阅读(149)  评论(0)    收藏  举报