因为孩子们总要跳出圈子,所以计算出的要删除的索引应该是相对目前的孩子总数而言的,这里用Delete函数删除并返回删除的那个孩子的初始标号。
还有关于一个整数的约数的个数的的问题,这里我采用了打表的方法。1750ms
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
using namespace std;
#define N 500005
int candysum[N];
struct node{
int l, r, num;
}Tree[N * 5];
int a[N];
char name[N][15];
void init()
{
memset(candysum, 0, sizeof(candysum));
for (int i = 1; i < N; i++)
{
++candysum[i];
for(int j = i * 2; j < N; j += i)
++candysum[j];
}
}
void build(int l, int r, int x)
{
Tree[x].l = l;
Tree[x].r = r;
Tree[x].num = (r - l + 1);
if (l == r)return;
int mid = (l + r) / 2;
build(l, mid, x * 2);
build(mid + 1, r, x * 2 + 1);
}
int Delete(int tag, int x)
{
--Tree[x].num;
if (Tree[x].l == Tree[x].r)
{
return Tree[x].l;
}
int ans;
if (Tree[x * 2].num >= tag)
ans = Delete(tag, x * 2);
else
ans = Delete(tag - Tree[x * 2].num, x * 2 + 1);
return ans;
}
int main()
{
int n, k;
init();
// FILE* fp = fopen("in.txt", "r");
while (scanf( "%d", &n) != EOF)
{
scanf( "%d", &k);
int ans = 1;
int tmp = 1;
for (int i = 2; i <= n; i++)
{
if (candysum[i] > candysum[ans])
ans = i;
}
build(1, n, 1);
for (int i = 1; i <= n; i++)
scanf( "%s %d", name[i], a + i);
int sum = n;
for (int i = 1; i < ans; i++)
{
int cur = Delete(k, 1);
int m = a[cur];
sum--;
if (m > 0)
{
m--;
k = (k - 1 + sum + m)%sum + 1;
}
else k = (k - 1 + sum - (-m % sum) )% sum + 1;
}
printf("%s %d\n", name[Delete(k, 1)], candysum[ans]);
// getchar();
}
// getchar();
return 0;
}