POJ 2886 Who Gets the Most Candies(线段树+约瑟夫环)
来源:互联网 发布:ant java 版本 编辑:程序博客网 时间:2024/04/29 17:26
题目链接:POJ 2886 Who Gets the Most Candies
【题目】N个孩子顺时针坐成一个圆圈,从1~N编号,每个孩子手中有一张标有非零整数的卡片。第K个孩子先出圈,如果他手中卡片上的数字A>0,下一个出圈的是他左手边第A个孩子。A<0,下一个出圈的是他右手边第(-A)个孩子。第p个出圈的孩子会得到F(p)个糖果,F(p)为p的因子数。输出得到糖果数最多的孩子的名字及糖果数目。
【思路】孩子数目很大(1~500000),于是想到要用线段树来优化,然后就是模拟出圈过程。并更新最大糖果数目。然后因为是一个圈,编号就每次都要取模,因为取模结果总是0~num-1,而编号确实1~num,所以取模要编号K-1,求出结果后再K+1。
①A>0, 因为这个人出去了,那么后面的人的编号都会先减一所以这里的要K-2。于是下一个出圈的就应该是剩余孩子中的第((K-2+A)%num+num)%num+1个。
②A<0,因为这个人出去,对前面的人是没有影响的。于是下一个出圈的就应该是剩余孩子中的第((K-1+A)%num+num)%num+1个。
这里的F(p)我是直接数组暴力打表得来的,最后1500MS过了,看网上有一种反素数,更加快,有空去学。
【涨姿势】代码中注释的地方在问了学长之后搞明白了,有负数的时候必须模两次,比如-14%6,(-14+6)%6和((-14)%6+6)%6的结果是不一样的,也就是说n%k,当n大于k的负两倍时,第一次模能够让它保证值落在-1倍~1倍之间,第二次模让它变成正数。
下面贴代码:
/*** POJ 2886 Who Gets the Most Candies** Created by Rayn @@ 2014/05/09** 线段树*/#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>using namespace std;const int MAX = 500100;struct Child { char name[12]; int A;} child[MAX];int n, k, tree[MAX<<2], candy[MAX];void GetCandy() //计算约数{ memset(candy, 0, sizeof(candy)); int limit = (int)sqrt(MAX); for(int i=1; i<limit; ++i) { for(int j=i+1; j*i<MAX; ++j) { candy[i*j] += 2; } candy[i*i]++; } /* for(int i=1; i<=50; ++i) printf("candy[%d]: %d\n",i, candy[i]); printf("\n"); //*/}void BuildTree(int rt, int l, int r){ tree[rt] = r - l + 1; if(l == r) { return ; } int mid = (l + r) >> 1; BuildTree(rt<<1, l, mid); BuildTree(rt<<1|1, mid+1, r);}int Update(int rt, int l, int r, int val){ tree[rt]--; if(l == r) { return l; } int ans, mid = (l + r) >> 1; if(val <= tree[rt<<1]) ans = Update(rt<<1, l, mid, val); else ans = Update(rt<<1|1, mid+1, r, val-tree[rt<<1]); tree[rt] = tree[rt<<1] + tree[rt<<1|1]; return ans;}int main(){#ifdef _Rayn //freopen("in.txt", "r", stdin);#endif GetCandy(); while(scanf("%d%d", &n, &k) != EOF) { memset(tree, 0, sizeof(tree)); BuildTree(1, 1, n); for(int i=1; i<=n; ++i) { scanf("%s%d", child[i].name, &child[i].A); } int maxVal = -1, maxPos, pos; int num = n; for(int i=1; i<=n; ++i) { pos = Update(1, 1, n, k); num--; if(candy[i] > maxVal) { maxVal = candy[i]; maxPos = pos; } if(num == 0) break; /* ** 因为取模结果总是0~num-1,所以取模要编号k-1,求出结果后再+1。 ** A>0, 因为这个人出去了,那么后面的人的编号都会先减一 ** 所以这里的k要再-1。 ** A<0,因为这个人出去,对前面的人是没有影响的。 */ if(child[pos].A > 0) { k = ((k-2 + child[pos].A) % num + num) % num + 1; } else { //为何模两次就对了呢 //k = ((k-1 + child[pos].A + num) % num + 1; k = ((k-1 + child[pos].A) % num + num) % num + 1; } } printf("%s %d\n", child[maxPos].name, maxVal); }return 0;}
0 0
- 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? (线段树 约瑟夫环问题变种)
- 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?(线段树)
- 每天一个C++小程序(十九)--桶排序
- 不要一辈子靠技术生存
- Simple HTTP Server and Client in Python
- python在windows下安装第三方库
- VC++小技巧-Output窗口输出定位 .
- POJ 2886 Who Gets the Most Candies(线段树+约瑟夫环)
- PHP中的字符串 — 表示方法
- C语言 八皇后问题
- 转载中医偏方
- 阿里云搭建FTP服务器(非常适合新手)
- Python<7>while、for循环
- oracle学习
- 一款方便的IIS工具--iisapp
- Hadoop与HBase中遇到的问题