线段树题目,思路不难,关键是F(p),很难想清楚是神马,表示看了别人的题意解析才知道神马意思。反素数这玩意果断决定打表了,以后比赛随时带着这玩意得了。另外注意的是,反素数的因子个数不是连续变化的,有可能依次增加好几个因子,这点特别注意下。
其他就是依次剔除人了,知道人物当前位置和当前人物长度可轻易推出下次出列的人物位置,依次将人物出列直到答案的值。
代码:
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define delf int m=(l+r)>>1
const int N=555555;
int sum[N*4];
string name[N*4];
int card[N*4];
int sss[100]={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,720720};
int b[37]={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,1314521};
int n,K,c,n1;
void pushup(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void build(int l,int r,int rt)
{
if (l==r)
{
sum[rt]=1;
cin>>name[rt];
scanf("%d",&card[rt]);
return ;
}
delf;
build(lson);
build(rson);
pushup(rt);
return ;
}
void update(int k,int l,int r,int rt)
{
//cout<<l<<" "<<r<<" "<<c<<" "<<n1<<endl;
if (l==r)
{
sum[rt]=0;
n1--;
c--;
//cout<<name[rt]<<endl;
if (c==0)
cout<<name[rt]<<" ";
else
{
if (card[rt]>0)
K=K+card[rt]-1;
else
K=K+card[rt];
while (K<0)
K=K+n1;
K=K%n1;
if (K==0)
K=n1;
}
return ;
}
delf;
if (sum[rt<<1]>=k)
update(k,lson);
else
update(k-sum[rt<<1],rson);
pushup(rt);
return ;
}
int main()
{
while (scanf("%d%d",&n,&K)!=EOF)
{
build(1,n,1);
c=0;
while (sss[c]<=n)
c++;
int ans=b[c-1];
c=sss[c-1];
//cout<<c<<endl;
n1=n;
while (c>0)
{
update(K,1,n,1);
//cout<<"AAAAA "<<K<<endl;
}
cout<<ans<<endl;
}
}