POJ 2886 Who Gets the MostCandies?(线段树+模拟+求数的约数个数)
2014-03-26 00:02
99 查看
POJ 2886 Who Gets the MostCandies?(线段树+模拟+求数的约数个数)http://poj.org/problem?id=2886
题意:
分析: 其实本题就是模拟每轮游戏,然后在每一轮游戏中先算出当前需要出队的第j个孩子,然后用线段树找到还在队中的第j个还是得原始编号。 首先建立一棵线段树,其每个叶节点都是1(代表每个孩子都在圈中,如果第i个孩子不在圈中,那么就令第i个叶子(孩子的编号不是i而是i管理的区间l或r)sum=0)。分析题中的例子:4 2Tom 2Jack 4Mary -1Sam 1 假设我们第一个出去的孩子是第2个孩子,那么我们把第二个叶节点的值置为0,该步只需要通过update找到sum值正好为2的那个区间的右端点(且该右端点的sum值也为1)即可。然后让这个sum变为0,表示这个孩子出了圈。并且我们读到了JACK的val值为4,当前圈剩余3个人,所以我们向后找4%3=1个人,如果[3,n]内的sum和>=1,那么直接在JACK右边即[3,n]区间找即可。如果sum的和<1,那么就在JACK左边[1,1]内找1-sum的那个位置的1. 依次类推即可。线段树的每个叶节点维护name,val,sum三个值,非叶节点只需要维护sum值即可。AC代码:1672ms
题意:
n个孩子按顺时针排列,每个人手上都有一张牌,牌上有一个数字,从第k个孩子开始出队,出队的孩子卡上数字是val,则从他开始顺时针第val人是下一个出队的,负数则逆时针数那个第val个人,第P个出队的会得到的糖果数是p的因子个数,输出得到最多糖果的人和他的糖果数,如果有多个,则输出最先出队的人。
分析: 其实本题就是模拟每轮游戏,然后在每一轮游戏中先算出当前需要出队的第j个孩子,然后用线段树找到还在队中的第j个还是得原始编号。 首先建立一棵线段树,其每个叶节点都是1(代表每个孩子都在圈中,如果第i个孩子不在圈中,那么就令第i个叶子(孩子的编号不是i而是i管理的区间l或r)sum=0)。分析题中的例子:4 2Tom 2Jack 4Mary -1Sam 1 假设我们第一个出去的孩子是第2个孩子,那么我们把第二个叶节点的值置为0,该步只需要通过update找到sum值正好为2的那个区间的右端点(且该右端点的sum值也为1)即可。然后让这个sum变为0,表示这个孩子出了圈。并且我们读到了JACK的val值为4,当前圈剩余3个人,所以我们向后找4%3=1个人,如果[3,n]内的sum和>=1,那么直接在JACK右边即[3,n]区间找即可。如果sum的和<1,那么就在JACK左边[1,1]内找1-sum的那个位置的1. 依次类推即可。线段树的每个叶节点维护name,val,sum三个值,非叶节点只需要维护sum值即可。AC代码:1672ms
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 500000+100; #define lson i*2,l,m #define rson i*2+1,m+1,r int sum[MAXN*4]; int cnt; struct node { char name[10]; int val; }nodes[MAXN]; void PushUp(int i) { sum[i]=sum[i*2]+sum[i*2+1]; } void build(int i,int l,int r) { if(l==r) { sum[i]=1; return ; } int m=(l+r)/2; build(lson); build(rson); PushUp(i); } int update(int q,int i,int l,int r)//找到第q个sum为1的叶节点,并返回其在线段树中的节点编号 { if(l==r) { sum[i]=0; return l; } int m=(r+l)/2; int res; if(q<=sum[2*i]) res= update(q,lson); else res= update(q-sum[2*i],rson); PushUp(i); return res; } int f[500010];//f[i]=x表示i的约数有x个 void get_f() { int i,j; for(i=1;i<=500000;i++) for(j=1;i*j<=500000;j++) { f[i*j]++;//假设x=i*j,那么i*j和j*i时,f[x]都会++,正好是加上了i和j各一次。 } } int main() { int n,k; memset(f,0,sizeof(f)); get_f(); while(scanf("%d%d",&n,&k)==2&&n&&k) { build(1,1,n); for(int i=1;i<=n;i++) { scanf("%s%d",nodes[i].name,&nodes[i].val); } if(n==1) { printf("%s 1\n",nodes[1].name); continue; } int j=k; int ans=0; char ans_name[10]; cnt=n;//cnt为当前有效叶节点的总数 for(int i=1;i<=n;i++) { //printf("j=%d\n",j); int num=update(j,1,1,n);//num是指原始序列的第num个孩子,j是指线段树区间[1,n]内的第j个1 cnt--; int x= f[i]; int v=nodes[num].val; if(ans<x) { ans = x; strcpy(ans_name,nodes[num].name); } if(i==n) break; int l_num=j-1; int r_num=cnt-j+1; if(v<0)//用v值来得到下一个需要处理的j值 { v=(-v)%cnt; if(v==0)v=cnt; if(l_num>=v) j =l_num-v+1; else j=cnt-(v-l_num)+1; } else if(v>0) { v=v%cnt; if(v==0)v=cnt; if(r_num>=v)j=l_num+v; else j=v-r_num; } } printf("%s %d\n",ans_name,ans); } return 0; }
相关文章推荐
- 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?(单点更新)
- 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? (线段树)
- 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?(线段树)
- poj2886 Who Gets the Most Candies? 线段树加反素数
- POJ 2886 Who Gets the Most Candies?