POJ_2886
由于N比较大,如果像模拟约瑟夫环那样用链表模拟的话,每次查找操作的复杂度是O(N)的,时间上是不允许的。但如果我们用线段树来直接求每次轮到谁的话,每次就只需要O(logN)的时间了。
于是大概思路就是每次都通过线段树查找相应的位置,然后计算一下F(p)的值并更新结果即可。
#include<stdio.h>
#include<string.h>
#include<math.h>
#define MAXD 500010
int N, M, K, P, tree[4 * MAXD], card[MAXD], isprime[MAXD], prime[MAXD];
char name[MAXD][15];
void update(int cur)
{
tree[cur] = tree[2 * cur] + tree[2 * cur + 1];
}
void build(int cur, int x, int y)
{
int mid = (x + y) / 2, ls = 2 * cur, rs = 2 * cur + 1;
if(x == y)
{
tree[cur] = 1;
return ;
}
build(ls, x, mid);
build(rs, mid + 1, y);
update(cur);
}
void init()
{
int i;
for(i = 1; i <= N; i ++)
scanf("%s%d", name[i], &card[i]);
build(1, 1, N);
}
void reset(int cur, int x, int y, int k)
{
int mid = (x + y) / 2, ls = 2 * cur, rs = 2 * cur + 1;
if(x == y)
{
tree[cur] = 0;
return ;
}
if(k <= mid)
reset(ls, x, mid, k);
else
reset(rs, mid + 1, y, k);
update(cur);
}
void getf(int turn, int x, int &ans, int &ansx)
{
int i, j, res = 1;
for(i = 0; prime[i] <= turn; i ++)
if(turn % prime[i] == 0)
{
j = 1;
while(turn % prime[i] == 0)
turn /= prime[i], ++ j;
res *= j;
}
if(turn != 1)
res *= 2;
if(res > ans)
ans = res, ansx = x;
}
int sum(int cur, int x, int y, int t)
{
int mid = (x + y) / 2, ls = 2 * cur, rs = 2 * cur + 1;
if(y <= t)
return tree[cur];
if(t <= mid)
return sum(ls, x, mid, t);
else
return tree[ls] + sum(rs, mid + 1, y, t);
}
int Search(int cur, int x, int y, int k)
{
int mid = (x + y) / 2, ls = 2 * cur, rs = 2 * cur + 1;
if(x == y)
return x;
if(k <= tree[ls])
return Search(ls, x, mid, k);
else
return Search(rs, mid + 1, y, k - tree[ls]);
}
void change(int &x)
{
int i, j, k = card[x], n;
n = sum(1, 1, N, x);
if(k < 0)
{
k = (-k - 1) % tree[1] + 1;
if(n < k)
x = Search(1, 1, N, tree[1] - k + n + 1);
else
x = Search(1, 1, N, n - k + 1);
}
else
{
k = (k - 1) % tree[1] + 1;
if(tree[1] - n < k)
x = Search(1, 1, N, k - tree[1] + n);
else
x = Search(1, 1, N, n + k);
}
}
void solve()
{
int i, j, x = K, ans = 0, ansx;
for(i = 1; i <= N; i ++)
{
reset(1, 1, N, x);
getf(i, x, ans, ansx);
if(i != N)
change(x);
}
printf("%s %d\n", name[ansx], ans);
}
void prepare()
{
int i, j, k;
memset(isprime, -1, sizeof(isprime));
k = sqrt(500000 + 0.5), P = 0;
for(i = 2; i <= k; i ++)
if(isprime[i])
{
prime[P ++] = i;
for(j = i * i; j <= k; j += i)
isprime[j] = 0;
}
prime[P ++] = 1000003;
}
int main()
{
prepare();
while(scanf("%d%d", &N, &K) == 2)
{
init();
solve();
}
return 0;
}