有两点:
1、每个人得到的F(p)可以用反素数来刻画,所以通过之前的预处理,把所有需要使用到的反素数全部打表给出。
2、对于类似于约瑟夫环的处理,可以加入线段树的方式来刻画。线段树的两个子函数一如之前的两题。主函数部分略纠结。
借鉴点击打开链接成功AC.
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define maxn 500005
struct Tree
{
int l,r,num;
}tree[maxn<<2];
struct Children
{
char name[15];
int num;
}child[maxn];
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 };
int fact[]={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};
void build(int l,int r,int rt)
{
tree[rt].l=l;
tree[rt].r=r;
tree[rt].num=r-l+1;
if(l==r) return ;
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
}
int update(int pos,int rt)
{
int l,r;
l=tree[rt].l;
r=tree[rt].r;
tree[rt].num--;
if(l==r) return l;
int m=(l+r)>>1;
if(pos<=tree[rt<<1].num)
return update(pos,rt<<1);
else{
return update(pos-tree[rt<<1].num,rt<<1|1);
}
}
int main()
{
int i,n,k,ans;
while(~scanf("%d%d",&n,&k)){
for(int i=1;i<=n;i++)
scanf("%s%d",child[i].name,&child[i].num);
for(int i=0;antiPrime[i]<=n;i++){
ans=i;
}
build(1,n,1);
int ansid=0;
child[ansid].num=0;
for(int i=0;i<antiPrime[ans];i++){
int mod=tree[1].num;
if(child[ansid].num>0)
k=((k+child[ansid].num-2)%mod+mod)%mod+1;
else
k=((k+child[ansid].num-1)%mod+mod)%mod+1;
ansid=update(k,1);
}
printf("%s %d\n",child[ansid].name,fact[ans]);
}
return 0;
}