您的位置:首页 > 其它

POJ 2886 Who Gets the Most Candies?(线段树 + 约瑟夫环 + 反素数)

2013-10-26 20:45 537 查看
线段树 + 约瑟夫环 + 反素数

题目连接

题意 : N个人顺时针围成一圈,每个人有一张卡片,轮到某个人的时候进行以下操作 :1 , 这个人退出这个圈。2,如果这个人的卡片上的数字是正数X则向右数X个位置,otherwise向左数(-X)个位置。3被数到的那个人执行相同操作,直至没有人为止。4,如果原来的那个人是第K个,那么他将会获得P(K)颗糖。 注 : P(k)表示k的不同约数数量(可以是1或者本身)。

思路 : 首先给定一个数N的话可以利用反素数打表很快求出到底是第M个执行操作获得的Candies最多。 然后约瑟夫环模拟寻找第M个人是谁。另外可以用线段树保存绝对位置下标和执行寻找相对位置下标这一操作。

注意 :是卡片数字是正的往右数喔 。

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 500005;
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
int max(int a, int b){return a > b ? a : b;}

int ans[maxn][2];

char name[maxn][12];
int cov[maxn<<2], aa[maxn], n, k;
int inprime[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
}, MaxSize = 35, fg[40];

void pushup(int rt)
{
cov[rt] = cov[rt<<1] + cov[rt<<1|1];
}

void build(int rt, int l, int r)
{
if (l == r)
{
cov[rt] = 1;
return ;
}
int mid = (l + r) >> 1;
build(lson); build(rson);
pushup(rt);
}

void update(int rt, int l, int r, int pos)
{
if (l == r)
{
cov[rt] = 0;
return ;
}
int mid = (l + r) >> 1;
int lv = cov[rt<<1];
if (pos <= lv)update(lson, pos);
else update(rson, pos-lv);
pushup(rt);
}

int query(int rt, int l, int r, int pos)
{
if (l == r)
{
return l;
}
int mid = (l + r) >> 1, lv = cov[rt<<1];
if (pos <= lv)return query(lson, pos);
else return query(rson, pos-lv);
}

int ysf(int sx, int Mx, int num)
{
if (num == 2)return 1;
int res;
if (Mx <= 0)
{
Mx = -Mx;
if (Mx < sx)return sx - Mx;
if (Mx == sx)return num - 1;
Mx -= (sx-1);
res = (Mx - 1) % (num - 1) + 1;
return num - res;
}
else
{
res = Mx - (num - sx);
return (res + num - 2) % (num - 1) + 1;
}

}

void solve()
{
build(1, 1, n);
int kk = k, e = k, m = n;
for (int i = 2; i <= ans
[0]; i++)
{
update(1, 1, n, kk);
kk = ysf(kk, aa[e], m);
e = query(1, 1, n, kk);
m--;
}
printf("%s %d\n", name[e], ans
[1]);
}

int get(int x)
{
int cnt = 0;
for (int i = 1; i*i <= x; i++)if (x % i == 0)
{
cnt++;
if (x/i != i)cnt++;
}
return cnt;
}

void init()
{
int i;
memset(ans, 0, sizeof(ans));
for (i = 0; i < MaxSize; i++)
{
fg[i] = get(inprime[i]);
ans[inprime[i]][0] = inprime[i];
ans[inprime[i]][1] = fg[i];
}
int Maxfg = 0, Maxv = 0;
for (i = 1; i <= maxn-1; i++)
{
Maxv = ans[i][0] = max(ans[i][0], Maxv);
Maxfg = ans[i][1] = max(ans[i][1], Maxfg);
}
}

int main()
{
int i;
init();
while (scanf("%d%d", &n, &k) == 2)
{
for (i = 1; i <= n; i++)
scanf("%s%d", name[i], &aa[i]);
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  POJ 线段树