POJ 2886 Who Gets the Most Candies?
题目大意:
n个小孩做成一圈且按照1~n编号,每个孩子手里都有一个卡片上面有一个数。
先让第k个孩子出圈,如果他手里是一个数a,那么下一个出圈的是他左边第a个。第p个出圈的人会获得p的约数个数个糖果。问获得最多糖果的是谁?获得了多少个糖果。
解题思路:
1、数据范围比较大,类约瑟夫环的操作要让线段树来解决。建立数查找每次是编号为几的孩子出圈。
2、对于最多糖果的问题,本题还用到了反素数。反素数的定义:对于任何正整数x,其约数的个数记做g(x)。例如g(1)=1,g(6)=4。如果某个正整数x满足:对于任意i(0<i<x),都有g(i)<g(x),则称x为反素数。对于本题,设p为不大于N的反素数,则第p个出圈的孩子得到的糖果最多,为p的约数个数。
下面是代码:
#include<iostream> #include<cstdio> #include<string.h> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define maxn 500010 int sgt[maxn*4],n,k; int F[maxn]; int precnt; struct node { char name[15]; int val; } bx[maxn]; void build(int l,int r,int rt) { sgt[rt]=r-l+1; if(l==r)return ; int m=(l+r)>>1; build(lson); build(rson); } int update(int p,int l,int r,int rt) { sgt[rt]--; if(l==r) return l; int m=(l+r)>>1; if(sgt[rt<<1]>=p) return update(p,lson); else return update(p-sgt[rt<<1],rson); } const int pre[]= {1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,1260,1680,2520,5040,7560,10080,15120,20160,25200,27720,45360,50400,55440,83160,110880,166320,221760,277200,332640,498960,554400}; const int ans[]= {1,2,3,4,6,8,9,10,12,16,18,20,24,30,32,36,40,48,60,64,72,80,84,90,96,100,108,120,128,144,160,168,180,192,200,216}; int main() { precnt=35; while(~scanf("%d%d",&n,&k)) { build(1,n,1); for(int i=1; i<=n; i++) scanf("%s%d",&bx[i].name,&bx[i].val); int need,tag=0; while(pre[ tag ]<=n) tag++; tag--; //找出最大的糖果答案 need=pre[ tag ]; //最大的糖果数对应的P值 int pos=0; bx[0].val=0; while(need--) //线段树模拟寻找第P个孩子 { if(bx[pos].val>0) k= ( (k+bx[pos].val-2) % + sgt[1] ) % sgt[1] +1; else k= ( (k+ bx[pos].val-1) % sgt[1] + sgt[1]) % sgt[1] +1; pos=update(k,1,n,1); } printf("%s %d\n",bx[pos].name,ans[tag]); } return 0; }