线段树解约瑟夫环,求第i个出圈的人
反素数打的是discuss里的表
#include
<
iostream
>
#include
<
algorithm
>
using
namespace
std;
#define
MAXN 500001
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
,
665280
};
const
int
factorNum[]
=
{
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
,
224
};
struct
Node{
int
l,r,c;
}nod[
3
*
MAXN];
int
next[MAXN],n,k,kk;
char
name[MAXN][
12
];
void
buildtree(
int
u,
int
l,
int
r){
nod[u].c
=
r
-
l
+
1
;
nod[u].l
=
l;
nod[u].r
=
r;
if
(l
==
r)
return
;
buildtree(
2
*
u,l,(l
+
r)
/
2
);
buildtree(
2
*
u
+
1
,(l
+
r)
/
2
+
1
,r);
}
void
insert(
int
u,
int
k){
nod[u].c
--
;
if
(nod[u].l
==
nod[u].r){
kk
=
nod[u].l;
return
;
}
if
(nod[
2
*
u].c
>=
k)
insert(
2
*
u,k);
else
insert(
2
*
u
+
1
,k
-
nod[
2
*
u].c);
}
int
query(
int
u,
int
l,
int
r){
if
(l
<=
nod[u].l
&&
nod[u].r
<=
r)
return
nod[u].c;
int
res
=
0
;
if
(l
<=
nod[
2u
].r)
res
+=
query(
2
*
u,l,r);
if
(r
>=
nod[
2
*
u].l)
res
+=
query(
2
*
u
+
1
,l,r);
return
res;
}
int
main(){
int
i,ith,tag,
&
nn
=
nod[
1
].c;
while
(scanf(
"
%d%d
"
,
&
n,
&
k)
!=
EOF){
for
(i
=
1
;i
<=
n;i
++
)
scanf(
"
%s%d
"
,
&
name[i],
&
next[i]);
buildtree(
1
,
1
,n);
tag
=
0
;
while
(antiprime[tag]
<=
n)
//
返回antiprime中小于等于n的最大反素数下标tag
tag
++
;
tag
--
;
ith
=
antiprime[tag];
//
第ith个退出的人得到最多的糖
kk
=
0
;
next[kk]
=
0
;
while
(ith
--
){
if
(next[kk]
>
0
)
k
=
((k
+
next[kk]
-
2
)
%
nn
+
nn)
%
nn
+
1
;
else
k
=
((k
+
next[kk]
-
1
)
%
nn
+
nn)
%
nn
+
1
;
insert(
1
,k);
}
printf(
"
%s %d\n
"
,name[kk],factorNum[tag]);
}
return
0
;
}