POJ_2886_Who Gets The Most Candies_线段树+反素数
2014-09-22 19:09
330 查看
66666666
题意:
一群熊孩子按照顺时针编号,然后面向圆心坐着cosplay约瑟夫,每个小孩有一个不为0的数字,其绝对值小于等于10^8,从某一个小孩开始,他被整出圈子,如果他的数字x是正数,那他左边第x个小孩就是下一个出去的,如果他的数字是负数,那他右边第-x个小孩就是下一个出去的,游戏结束直到所有的熊孩子都被整出去了。第i个被整出去的熊孩子能拿到f(i)个糖果,f(i)是可以整除i的正整数个数。求哪个熊孩子拿到的糖最多,是多少。
Input
There are several test cases in the input. Each test case starts with two integers
N (0 < N ≤ 500,000) and K (1 ≤
K ≤ N) on the first line. The next N lines contains the names of the children (consisting of at most 10 letters) and the integers (non-zero with magnitudes within 108) on their cards in increasing order of the children’s
numbers, a name and an integer separated by a single space in a line with no leading or trailing spaces.
Output
Output one line for each test case containing the name of the luckiest child and the number of candies he/she gets. If ties occur, always choose the child who jumps out of the circle first.
这个问题难解决的是熊孩子出去以后他们的编号要变,当然用链表可以很好解决,但是一听说有糖10^5个熊孩子来做游戏,链表就没法破了,必须用O(logn)的算法解决查找下一个熊孩子的问题。于是就可以用线段树查找编号为i的熊孩子现在排在第几位,通过线段树记录区间内熊孩子的个数。模拟的过程调了好久。
另一个麻烦的是f(i)。网上大多数人是利用了反素数的概念。根据定义,一个数的约数个数小于任何一个小于他的 数字的约数个数,则它是一个反素数,500000内的反素数数量不多,可以打表解决。
但是看到了芳姐的博客里面的解法,用了埃氏筛法和dp。具体做法是先筛出所有的质数,然后循环所有数找他们约数个数。f(1)=1,i为质数f(i)=2,合数只需要跑个朴素质数测试找到它的一个质因数a,然后求出该质因数的次方b,dp[i]=dp[i/(a^b)]*(b+1)即可。
代码如下:
题意:
一群熊孩子按照顺时针编号,然后面向圆心坐着cosplay约瑟夫,每个小孩有一个不为0的数字,其绝对值小于等于10^8,从某一个小孩开始,他被整出圈子,如果他的数字x是正数,那他左边第x个小孩就是下一个出去的,如果他的数字是负数,那他右边第-x个小孩就是下一个出去的,游戏结束直到所有的熊孩子都被整出去了。第i个被整出去的熊孩子能拿到f(i)个糖果,f(i)是可以整除i的正整数个数。求哪个熊孩子拿到的糖最多,是多少。
Input
There are several test cases in the input. Each test case starts with two integers
N (0 < N ≤ 500,000) and K (1 ≤
K ≤ N) on the first line. The next N lines contains the names of the children (consisting of at most 10 letters) and the integers (non-zero with magnitudes within 108) on their cards in increasing order of the children’s
numbers, a name and an integer separated by a single space in a line with no leading or trailing spaces.
Output
Output one line for each test case containing the name of the luckiest child and the number of candies he/she gets. If ties occur, always choose the child who jumps out of the circle first.
这个问题难解决的是熊孩子出去以后他们的编号要变,当然用链表可以很好解决,但是一听说有糖10^5个熊孩子来做游戏,链表就没法破了,必须用O(logn)的算法解决查找下一个熊孩子的问题。于是就可以用线段树查找编号为i的熊孩子现在排在第几位,通过线段树记录区间内熊孩子的个数。模拟的过程调了好久。
另一个麻烦的是f(i)。网上大多数人是利用了反素数的概念。根据定义,一个数的约数个数小于任何一个小于他的 数字的约数个数,则它是一个反素数,500000内的反素数数量不多,可以打表解决。
但是看到了芳姐的博客里面的解法,用了埃氏筛法和dp。具体做法是先筛出所有的质数,然后循环所有数找他们约数个数。f(1)=1,i为质数f(i)=2,合数只需要跑个朴素质数测试找到它的一个质因数a,然后求出该质因数的次方b,dp[i]=dp[i/(a^b)]*(b+1)即可。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> using namespace std; #define mxn 600000 char name[mxn][20]; int num[mxn]; int ll[mxn<<2],rr[mxn<<2],sum[mxn<<2],indx[mxn<<2]; int n,k; void build(int l,int r,int id){ ll[id]=l,rr[id]=r; if(l==r){ sum[id]=1; indx[id]=l; return; } int m=(l+r)>>1,ls=id<<1,rs=ls|1; build(l,m,ls); build(m+1,r,rs); sum[id]=sum[ls]+sum[rs]; indx[id]=-1; } void update(int ind,int id){ if(ll[id]==rr[id]){ indx[id]=-1; sum[id]=0; return; } int m=(ll[id]+rr[id])>>1,ls=id<<1,rs=ls|1; if(ind<=m) update(ind,ls); else update(ind,rs); sum[id]=sum[ls]+sum[rs]; } int nxt(int ind,int id){ if(ll[id]==rr[id]) return 0; int m=(ll[id]+rr[id])>>1,ls=id<<1,rs=ls|1; if(ind>m) return sum[ls]+nxt(ind,rs); else return nxt(ind,ls); } int find(int nm,int id){ if(ll[id]==rr[id]) return indx[id]; int m=(ll[id]+rr[id])>>1,ls=id<<1,rs=ls|1; if(nm<sum[ls]) return find(nm,ls); else return find(nm-sum[ls],rs); } bool is_prime[mxn]; int candy[mxn]; void init(){ memset(is_prime,true,sizeof(is_prime)); memset(candy,0,sizeof(candy)); for(int i=2;i<mxn;++i) if(is_prime[i]) for(int j=i*2;j<mxn;j+=i) is_prime[j]=false; candy[1]=1; for(int i=2;i<mxn;++i){ if(is_prime[i]) candy[i]=2; else for(int j=2;j<i;++j) if(i%j==0){ int tem=i,cnt=0; while(tem%j==0){ ++cnt; tem/=j; } candy[i]=candy[tem]*(cnt+1); break; } } } int main(){ init(); while(scanf("%d%d",&n,&k)!=EOF){ for(int i=0;i<n;++i) scanf("%s%d",name[i],&num[i]); build(0,n-1,1); int cnt=n,ans=-10,tem,rec; --k; while(true){ --cnt; update(k,1); if(ans<candy[n-cnt]){ ans=candy[n-cnt]; rec=k; } if(!cnt) break; tem=nxt(k,1); tem+=num[k]; if(num[k]>0) --tem; while(tem<0) tem+=(1+(-tem)/cnt)*cnt; k=tem%cnt; k=find(k,1); } printf("%s %d\n",name[rec],ans); } return 0; }
相关文章推荐
- POJ 2886 Who Gets the Most Candies?(线段树+反素数)
- poj 2886 Who Gets the Most Candies?(线段树+反素数)
- 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?(反质数+线段树模拟约瑟夫)
- 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?(线段树#3)
- 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?