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


浙公网安备 33010602011771号