poj2886 Who Gets the Most Candies?

题意:输入n,k表示n个人,第k个第一个离开圆环,之后n行,每行一个名字和一个数字m,表示从这个人开始顺时针(数字大于0)或逆时针(数字小于0)第m个人离开圆环。每个人离开时会有一个得分,得分=F(离开次序i); F(i)=能整除i的数的个数;求这个人的名字和得分。


思路:首先打表枚举[1,500000]的F(i);  然后模拟求这个人的名字,对于[1,n]中,求出是F(i)最大的i值,模拟i次离开就行了。人数比较多,直接模拟肯定不行,需要借助线段树(树状数组)直接计算出要离开圆环的人的坐标,线段树中维护的是这个区间中还剩下几个人。


很多人都把反素数表打了出来,我直接在代码中计算的,只会耗费大约300MS。


我自己写的(2700MS):

#include
#include
#include
#include
#include
#include
#include
#include
#include
#define maxn 510000

using namespace std;

struct node
{
	char name[50];
	int next;
	int score;
}tp[maxn];
int num[maxn];
struct tree
{
	int l,r;
	int sum;
}tr[maxn*3];

void update(int o,int l,int r,int pos,int v)
{
	int m=(l+r)/2;
	if(l==r)
	{
		tr[o].sum=v;
	}
	else
	{
		if(pos<=m)
			update(o*2,l,m,pos,v);
		else
			update(o*2+1,m+1,r,pos,v);
		tr[o].sum=tr[o*2].sum+tr[o*2+1].sum;
	}
}
int query(int o,int l,int r ,int ql,int qr)
{
	int m=(l+r)/2;
	if(ql>qr)
		return 0;
	if(ql<=l && r<=qr)
		return tr[o].sum;
	int ans=0;
	if(ql<=m)
		ans+=query(o*2,l,m,ql,qr);
	if(m=pos)
		return _find(o*2,l,m,pos);
	else
		return _find(o*2+1,m+1,r,pos-tr[o*2].sum);
}
int main()
{
	int n,k;
	calcu();
	while(scanf("%d%d",&n ,&k)!=EOF)
	{
		int mmax=0,pmax;
		for(int i=1;i<=n;++i)
		{
			if(num[i]>mmax)
			{
				mmax=num[i];
				pmax=i;
			}
		}
		memset(tr,0,sizeof(tr));
		for(int i=0;i=0)
			{
				if(re!=0)
					mov=mov%re;
				if(mov==0)
					mov=re;
			}
			else
			{
				if(re!=0)
					mov=-(abs(mov)%re);
				mov+=re+1;
				if(re!=0)
					mov%=re;
				if(!mov)
					mov=re;
			}
			update(1,0,n-1,k-1,0);
			int re_l=query(1,0,n-1,0,k-1);
			int re_r=query(1,0,n-1,k,n-1);
			if(mov>re_r)
			{
				mov-=re_r;
			}
			else
			{
				mov+=re_l;
			}
			k=_find(1,0,n-1,mov)+1;
		}
		cout<

看了别人写的后改进的(1700MS,把反素数表打出来还能再节省300MS):

#include
#include
#include
#include
#include
#include
#include
#include
#include
#define maxn 510000

using namespace std;

struct node
{
	char name[50];
	int next;
	int score;
}tp[maxn];
int num[maxn];
struct tree
{
	int l,r;
	int sum;
}tr[maxn*3];

void ini(int o,int l,int r)
{
	if(l==r)
	{
		tr[o].sum=1;
		return ;
	}
	if(l>r)
		return ;
	tr[o].sum=(r-l)+1;
	int m=(l+r)/2;
	ini(o*2,l,m);
	ini(o*2+1,m+1,r);
}
void calcu()
{
	memset(num,0,sizeof(num));
	for(int i=1;i=pos)
		return _find(o*2,l,m,pos);
	else
		return _find(o*2+1,m+1,r,pos-tr[o*2].sum);
}
int main()
{
	int n,k;
	calcu();
	while(scanf("%d%d",&n ,&k)!=EOF)
	{
		int mmax=0,pmax;
		for(int i=1;i<=n;++i)
		{
			if(num[i]>mmax)
			{
				mmax=num[i];
				pmax=i;
			}
		}
		memset(tr,0,sizeof(tr));
		for(int i=0;i=0)
			{
				mov=(k-1+mov)%re;
				if(mov==0)
					mov=re;
			}
			else
			{
				mov=-(abs(mov)%re);
				mov+=re+1;
				mov=(mov+k-1)%re;
				if(mov==0)
					mov=re;
			}
			k=mov;
		}
		cout<



你可能感兴趣的:(线段树,poj训练计划,poj,poj2886)