poj 2886 Who Gets the Most Candies?(线段树、反素数)


poj 2886 Who Gets the Most Candies?


此题线段树的思路倒是没什么问题,关键在于求1-N中约束个数最大那个数,当然如果知道反素数就没什么问题了,一开始不知道,打个表、、果断TLE

反素数详解


#include<stdio.h>
#include<string.h>
#include<math.h>
#define MAXN 500005
#define lch p<<1
#define rch p<<1|1
#define mid (t[p].l+t[p].r)>>1
int rprime[]={//反素数  
    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  
};  
  
int fact[]={//反素数约数个数  
    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  
}; 
struct node
{
	int l,r;
	int sum;
}t[MAXN<<2];
void pushup(int p) {t[p].sum=t[lch].sum+t[rch].sum;}
void construct(int l,int r,int p)
{
	t[p].l=l,t[p].r=r;
	if(l==r)
	{
		t[p].sum=1;
		return ;
	}
	int m=mid;
	construct(l,m,lch);
	construct(m+1,r,rch);
	pushup(p);
}
void modify(int x,int p)
{
	if(t[p].l==t[p].r)
	{
		t[p].sum=0;
		return ;
	}
	int m=mid;
	if(x<=m) modify(x,lch);
	else modify(x,rch);
	pushup(p);
}
int query(int x,int p)
{
	if(t[p].l==t[p].r)
		return t[p].l;
	if(x<=t[lch].sum) return query(x,lch);
	else return query(x-t[lch].sum,rch);
}
struct child
{
	char name[12];
	int num;
}c[MAXN];
int main()
{
	int n,k;
	while(scanf("%d%d",&n,&k)!=EOF)
	{
		construct(1,n,1);
		for(int i=1;i<=n;i++)
			scanf("%s%d",c[i].name,&c[i].num);
		int ansi=0;
		int i=0;
		while(n>=rprime[i])
			ansi=i++;
		int cnt=0,pos=0;
		while(n)
		{
			if(c[pos].num>0)
				k=((k+c[pos].num-1)%n+n)%n;
			else
				k=((k+c[pos].num)%n+n)%n;
			pos=query(k,1);
			cnt++;
			if(cnt==rprime[ansi])
			{
				printf("%s %d\n",c[pos].name,fact[ansi]);
				break;
			}
			modify(pos,1);
			n--;
		}
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值