POJ 2886 Who Gets the Most Candies?(线段树单点更新+反素数)

Who Gets the Most Candies?
Time Limit: 5000MS Memory Limit: 131072K
Total Submissions: 8334 Accepted: 2504
Case Time Limit: 2000MS

Description

N children are sitting in a circle to play a game.

The children are numbered from 1 to N in clockwise order. Each of them has a card with a non-zero integer on it in his/her hand. The game starts from the K-th child, who tells all the others the integer on his card and jumps out of the circle. The integer on his card tells the next child to jump out. Let A denote the integer. If A is positive, the next child will be the A-th child to the left. If A is negative, the next child will be the (−A)-th child to the right.

The game lasts until all children have jumped out of the circle. During the game, the p-th child jumping out will get F(p) candies where F(p) is the number of positive integers that perfectly divide p. Who gets the most candies?

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.

Sample Inpu t

4 2
Tom 2
Jack 4
Mary -1
Sam 1

Sample Output

Sam 3

Source

POJ Monthly--2006.07.30, Sempr


题意:

有n个人顺时针围坐成一个圈,每个人手上都有一张卡片,开始去点第k个人,第k个人先退出,接着用刚才那第k个人手上的卡片去点名,正数顺时针点名,负数逆时针点名,重复执行,直到所有人都退出为止。每个人退出都可一得到糖果,第i个退出可以的到他的F(i)颗糖果。输出得到最多糖果的人的名字和糖果数,如果有糖果数相同的以先退出的为准。

F(i)即i元素的因子数之和。例:F(6)=4(1,2,3,6);F(15)=4(1,3,5,15);

思路:

1.例:F(1)=1;F(2)=2;F(3)=2;F(4)=3;F(5)=2;F(6)=4;可以看出F(i)不是线性增大的,所以在一个n范围内就有一个F(i)是最大的,需要用打表把他们处理出来。  见代码1,此程序效率并不高,见谅。

2.运用线段树单点更新,求出下一个人要退出的相对位置。例:假设共10个人,1,2,3,4......8,9,10;此时4,6,8已经退出,当前要退出的是第2个,第2个手里的卡片值是4,那么下一个要退出的确切位置是在第9个,而相对位置是第6个。

代码1,打表

/*************************************************************************
	> File Name: 2886.cpp
	> Author: BSlin
	> Mail:  
	> Created Time: 2013年09月18日 星期三 13时18分28秒
 ************************************************************************/

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iterator>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#define MP make_pair
#define INF (1<<30)
#define PI acos(-1.0)
#define esp 1e-8
const int dx[4]={0,0,0,0};
using namespace std;
#define read freopen("in.txt","r",stdin)
#define write freopen("out.txt","w",stdout)
#if defined (_WIN32) || defined (__WIN32) || defined (WIN32) || defined (__WIN32__)
#define LL __int64
#define LLS "%" "I" "6" "4" "d"
#else
#define LL long long
#define LLS "%" "l" "l" "d"
#endif


int mark[710],prime[130],sum_max,num_min;
int cnt,MAX;
void dfs(int sum,int num,int k,int limit) {
	int i;
	if(sum > sum_max) {
		sum_max = sum;
		num_min = num;
	}
	if(sum == sum_max && num < num_min) num_min = num; 
	if(k>=cnt) return ;
	for(i=1;i<=limit;i++){
		if(prime[k]*num>MAX) break;
		num = prime[k] * num;
		dfs(sum*(i+1),num,k+1,i);
	}
}
int main(int argc, char** argv) {
	//write;
	memset(mark,0,sizeof(mark));
	cnt = 0;
	int ans;
	for(int i=2;i<=709;i++){
		if(mark[i] == 0) {
			prime[cnt++] = i;
		}
		for(int j=0;j<cnt;j++){
			if(i*prime[j]>709) break;
			mark[i*prime[j]] = prime[j];
			if(mark[i] == prime[j]) break;
		}
	}
	ans = 0;
	sum_max=0;
	num_min=0;
	for(MAX = 1;MAX<580000;MAX++){
		dfs(1,1,0,25);
		if(ans!=num_min){
			printf("%d,",num_min);
			ans = num_min;
		}
	}
	printf("\n");
	ans = 0;
	sum_max=0;
	num_min=0;
	for(MAX = 1;MAX<580000;MAX++){
		dfs(1,1,0,25);
		if(ans!=sum_max){
			printf("%d,",sum_max);
			ans = sum_max;
		}
	}
    return 0;
}

代码2,主代码

/*************************************************************************
	> File Name: poj2886.cpp
	> Author: BSlin
	> Mail:  
	> Created Time: 2013年09月18日 星期三 13时03分09秒
 ************************************************************************/

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iterator>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#define MP make_pair
#define INF (1<<30)
#define PI acos(-1.0)
#define esp 1e-8
const int dx[4]={0,0,0,0};
using namespace std;
#define read freopen("in.txt","r",stdin)
#define write freopen("out.txt","w",stdout)
#if defined (_WIN32) || defined (__WIN32) || defined (WIN32) || defined (__WIN32__)
#define LL __int64
#define LLS "%" "I" "6" "4" "d"
#else
#define LL long long
#define LLS "%" "l" "l" "d"
#endif

#define M 500010

struct node {
    int L,R,lnum,rnum;
}tree[M<<2];

char name[M][15];
int out[40]={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},candies[40]={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};
//需要比500000大一些,原因看下面的注释
int pos[M],now_pos;
void up(int p) {
    tree[p].lnum = tree[p<<1].lnum + tree[p<<1].rnum;
    tree[p].rnum = tree[p<<1|1].lnum  + tree[p<<1|1].rnum;
}

void build(int L,int R,int p) {
    tree[p].L = L;
    tree[p].R = R;
    if(L == R) {
        tree[p].lnum = 1;
        tree[p].rnum = 0;
        return ;
    }
    int mid = (L + R) >> 1;
    build(L,mid,p<<1);
    build(mid+1,R,p<<1|1);
    up(p);
}

void update(int out_num,int p) {
    if(tree[p].L == tree[p].R){
        now_pos = tree[p].L;
        tree[p].lnum = 0;
        return; 
    }
    if(out_num <= tree[p].lnum)
        update(out_num,p<<1);
    else if(out_num - tree[p].lnum <= tree[p].rnum)
        update(out_num - tree[p].lnum,p<<1|1);
    up(p);
}

int main(int argc, char** argv) {
    read;
    int n,k,i,candie,time;
    while(scanf("%d%d",&n,&k) != EOF) {
        build(1,n,1);
        i=0;
        while(out[i] <= n){      //当n在500000左右时,会发生错误
            i++;
        }
        i--;
        candie = candies[i];
        time = out[i];
        for(int i=1;i<=n;i++){
            scanf("%s%d",&name[i][0],&pos[i]);
        }
        now_pos = 0;
        pos[0] = 0;
        int cc=n;
        for(int i=time;i>=1;i--){
            if(pos[now_pos]>0){
                k = ((k + pos[now_pos] - 1) % cc + cc) % cc; 
                if(k == 0) k = cc;
            } 
            else{
                k = ((k + pos[now_pos]) % cc + cc) % cc;
                if(k == 0) k = cc;
            } 
            cc--;
            update(k,1);
        }
        printf("%s %d\n",name[now_pos],candie);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值