题目链接点击打开链接
题目大意:给出n个人的姓名和手里的一个号码,n个人排成一圈,号码有正有负,代表着正向还是反向移动k个位置,比赛从第k个人开始,把被选到的人踢出,问按踢出的顺序中因子数最多的是谁?
建立线段树,把n个人被踢的顺序找到,然后求出n个人中因子数最多的(最小的数)是谁,这里要用到反素数,详看链接点击打开链接
#include <cstdio> #include <cstring> #include <algorithm> using namespace std ; #define lson l,(l+r)/2,rt<<1 #define rson (l+r)/2+1,r,rt<<1|1 #define root 1,n,1 #define int_rt int l,int r,int rt int a[8] = {2,3,5,7,11,13,17,19} ; int cl[2010000] ; char str[510000][12] ; int p[510000] , w[510000] , cnt ; int n , ans , best ; void push_up(int rt) { cl[rt] = cl[rt<<1] + cl[rt<<1|1] ; } void creat(int_rt) { if( l == r ) cl[rt] = 1 ; else { creat(lson) ; creat(rson) ; push_up(rt) ; } } int update(int k,int_rt) { if( l == r ) { cl[rt] = 0 ; return l ; } if( cl[rt<<1] >= k ) k = update(k,lson) ; else k = update(k-cl[rt<<1],rson) ; push_up(rt) ; return k ; } void dfs(int dept,int temp,int num) { if( dept >= 8 ) return ; if( num > best ) { best = num ; ans = temp ; } if( num == best && temp < ans ) ans = temp ; for(int i = 1 ; i < 25 ; i++) { if( n/a[dept] < temp ) break ; temp *= a[dept] ; dfs(dept+1,temp,num*(i+1)) ; } } int main() { int m , k , i ; while( scanf("%d %d", &n, &k) != EOF ) { for(i = 1 ; i <= n ; i++) { scanf("%s %d", str[i], &p[i]) ; } creat(root) ; cnt = 1 ; while( 1 ) { m = update(k,root) ; w[m] = cnt++ ; if( !cl[1] ) break ; if( p[m] >= 0 ) { k = (k+p[m]-1)%cl[1] ; if( !k ) k = cl[1] ; } else { k = (k-cl[1]-1+p[m])%cl[1] ; if( !k ) k = 1 ; else k = cl[1]+1+k ; } } best = 0 ; ans = n ; dfs(0,1,1) ; for(i = 1 ; i <= n ; i++){ if( w[i] == ans ) { printf("%s %d\n", str[i], best) ; break ; } } } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-11-02 15:32:46