大意略。
通过此题学习到了反素数与用线段树模拟约瑟夫环的应用。其中,相对位置的求解比较难懂额。
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
const int maxn = 500010;
int n, k;
int pos;
int sum[maxn<<2];
const int antiprime[] = {
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};
const int facnum[] = {
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};
struct node
{
char name[110];
int value;
}A[maxn];
void build(int o , int L, int R)
{
int M = L + (R-L)/2;
sum[o] = R-L+1;
if(L == R) return ;
else
{
build(o*2, L, M);
build(o*2+1, M+1, R);
}
}
void update(int p, int o, int L, int R)
{
int ret;
int M = L + (R-L)/2;
sum[o]--;
if(L == R) pos = L;
else
{
if(p <= sum[2*o]) update(p, o*2, L, M);
else
{
p -= sum[2*o];
update(p, 2*o+1, M+1, R);
}
}
}
void read_case()
{
build(1, 1, n);
for(int i = 1; i <= n; i++) scanf("%s %d", A[i].name, &A[i].value);
}
void solve()
{
read_case();
int i = 0;
while(antiprime[i] <= n) i++;
i--;
int p = antiprime[i];
int ans = facnum[i];
pos = 0;
A[pos].value = 0;
for(int i = 1; i <= p; i++)
{
int mod = sum[1];
if(A[pos].value > 0) k = (k-1+A[pos].value-1)%mod+1; //相对位置
else k = ((k-1+A[pos].value)%mod+mod)%mod+1; //相对位置
update(k, 1, 1, n);
}
printf("%s %d\n", A[pos].name, ans);
}
int main()
{
while(~scanf("%d%d", &n, &k))
{
solve();
}
return 0;
}