POJ 2886 Who Gets the Most Candies?(线段树)
2013-08-03 17:44
483 查看
题意:N 个小孩围成一圈,他们被顺时针编号为 1 到 N。每个小孩手中有一个卡片,上面有一个非 0 的数字,游戏从第 K 个小孩开始,他告诉其他小孩他卡片上的数字并离开这个圈,他卡片上的数字 A 表明了下一个离开的小孩,如果 A 是大于 0 的,则下个离开的是左手边第
A 个,如果是小于 0 的,则是右手边的第 -A 个小孩。游戏将直到所有小孩都离开,在游戏中,第 p 个离开的小孩将得到 F(p) 个糖果,F(p) 是 p 的约数的个数,问谁将得到最多的糖果。输出最幸运的小孩的名字和他可以得到的糖果。
思路:其实只要知道P=max{F(i)}(1<=i<=N)就可以了,P就是反素数,然后用线段树加速模拟小孩出圈的过程。
对于反素数的求法,先用筛法求出50w以内的素数,并记录下每个数的任意一个因数。现在设f(i)为i的约数个数,如果i是素数,则f(i)=2。如果i是合数,令i=a1^b1*a2^b2*…*an^bn,则i的约数个数为(b1+1)*(b2+1)*...*(bn+1)。因此,可以用递推式f(i)=f(i/ak)*(bk+1)/bk(其中ak是i的任意一个约数)。其实还可以打表记录反素数,这里不作介绍。
线段树的维护,每次用二差查找的方法寻找每次出圈孩子的位置并更新就可以了。具体方法和POJ 2828类似,这里不作详细说明。
注意卡片上的值为正和为负的时候,计算位移时应该分开讨论。
A 个,如果是小于 0 的,则是右手边的第 -A 个小孩。游戏将直到所有小孩都离开,在游戏中,第 p 个离开的小孩将得到 F(p) 个糖果,F(p) 是 p 的约数的个数,问谁将得到最多的糖果。输出最幸运的小孩的名字和他可以得到的糖果。
思路:其实只要知道P=max{F(i)}(1<=i<=N)就可以了,P就是反素数,然后用线段树加速模拟小孩出圈的过程。
对于反素数的求法,先用筛法求出50w以内的素数,并记录下每个数的任意一个因数。现在设f(i)为i的约数个数,如果i是素数,则f(i)=2。如果i是合数,令i=a1^b1*a2^b2*…*an^bn,则i的约数个数为(b1+1)*(b2+1)*...*(bn+1)。因此,可以用递推式f(i)=f(i/ak)*(bk+1)/bk(其中ak是i的任意一个约数)。其实还可以打表记录反素数,这里不作介绍。
线段树的维护,每次用二差查找的方法寻找每次出圈孩子的位置并更新就可以了。具体方法和POJ 2828类似,这里不作详细说明。
注意卡片上的值为正和为负的时候,计算位移时应该分开讨论。
#include<cstdio> #include<cstring> #define M ((L+R)>>1) #define ls (o<<1) #define rs (o<<1|1) #define lson ls,L,M #define rson rs,M+1,R #define MAXN 500005 char name[MAXN][12]; int n,pos,A[MAXN],sumv[MAXN*3],num; //sumv[o]储存根o的区间内还剩多少个小孩,初始化时叶子结点为1 //线段树的维护 void pushup(int o) {sumv[o]=sumv[ls]+sumv[rs];} void build(int o,int L,int R) { if(L==R) {sumv[o]=1;return;} build(lson); build(rson); pushup(o); } void update(int o,int L,int R,int sum) { if(L==R) {sumv[o]=0;num=L;return;} sumv[ls]+sum>=pos? update(lson,sum):update(rson,sum+sumv[ls]); pushup(o); } //==========================================/ //求约数个数部分 int f[MAXN],fmax[MAXN],fmaxnum[MAXN],prime[MAXN],pnum=0,yinshu[MAXN]; bool isprime[MAXN]; void init_fmax() { memset(isprime,0,sizeof(isprime)); f[1]=fmax[1]=fmaxnum[1]=isprime[0]=isprime[1]=1; for(int i=2;i<MAXN;++i) { if(!isprime[i]) prime[pnum++]=i; for(int j=0;j<pnum && prime[j]*i<MAXN;++j) { isprime[prime[j]*i]=1; yinshu[prime[j]*i]=prime[j]; //记录约数 if(i%prime[j]==0) break; } if(!isprime[i]) f[i]=2; else { int tn=i,bi=0; while(tn>1 && tn%yinshu[i]==0) tn/=yinshu[i],++bi; f[i]=f[i/yinshu[i]]*(bi+1)/bi; } if(f[i]>fmax[i-1]) fmax[i]=f[i],fmaxnum[i]=i; else fmax[i]=fmax[i-1],fmaxnum[i]=fmaxnum[i-1]; } } //========================================================/ int main() { init_fmax(); while(~scanf("%d%d",&n,&pos)) { for(int i=1;i<=n;++i) scanf(" %s %d",name[i],&A[i]); build(1,1,n); for(int i=1;i<fmaxnum ;++i)//剩下n-i个人 { update(1,1,n,0); if(A[num]<0) pos+=A[num]-1; else pos+=A[num]-2; while(pos<0) pos+=(n-i); pos=pos%(n-i)+1; } update(1,1,n,0); printf("%s %d\n",name[num],fmax ); } return 0; }
相关文章推荐
- POJ 2886 Who Gets the Most Candies?(线段树)
- POJ 2886 Who Gets the Most Candies(线段树模拟约瑟夫环)
- POJ 2886 Who Gets the Most Candies? (高合成数&用线段树维护约瑟夫环)
- POJ Who Gets the Most Candies? 2886(线段树)
- POJ2886-Who Gets the Most Candies?-模拟约瑟夫环+反素数表(线段树上二分+爆搜打表)
- POJ 2886 Who Gets the Most Candies? (线段树)
- poj 2886 Who Gets the Most Candies?(线段树单点更新)
- POJ 2886 Who Gets the Most Candies?(线段树模拟约瑟夫环,高合成数)
- POJ 2886 Who Gets the Most Candies? (打表+线段树)
- POJ 2886 Who Gets the Most Candies? (线段树)
- poj 2886 Who Gets the Most Candies?(线段树)
- poj 2886 Who Gets the Most Candies?(线段树、反素数)
- poj 2886 Who Gets the Most Candies?(线段树-单点更新)
- POJ 2886 Who Gets the Most Candies? (线段树 约瑟夫环问题变种)
- POJ 2886 Who Gets the Most Candies? [线段树-单点更新]【数据结构】
- POJ 2886 Who Gets the Most Candies?(线段树 + 约瑟夫环 + 反素数)
- (中等) POJ 2886 Who Gets the Most Candies? , 反素数+线段树。
- POJ-2886-Who Gets the MostCandies?-(线段树)
- POJ 2886 Who Gets the Most Candies? 线段树
- POJ 2886 Who Gets the Most Candies? 线段树单点更新