题意:N个小孩围成一圈,玩约瑟夫环,每个小孩有一张卡片上面是数字a,正数代表右手边第a个小孩出队,负数表示左手边,游戏从第k个小孩开始,游戏直到所有小孩出队为止,第p个出队小孩得到f[p]分数,f[p]为p的因子数
题解:这里引入反素数的概念不清楚可以看http://blog.csdn.net/ACdreamers/article/details/25049767
每次询问只要从第一个出队的运行到当前给出的n范围内的最大反素数即可,然后和poj2828类似 线段树tree记录当前线段上有多少个人 然后主要就是数数的问题了 比较难理解http://blog.csdn.net/shiqi_614/article/details/6849406
#include<cstdio>
#include<cstring>
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int N=500010;
int tree[N<<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,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 child
{
char name[15];
int val;
}c[N];
void build(int l,int r,int rt)
{
tree[rt]=r-l+1;
if(l==r)return;
int mid=(l+r)>>1;
build(lson);build(rson);
}
int update(int p,int l,int r,int rt)
{
tree[rt]--;
if(l==r) return l;
int mid=(l+r)>>1;
if(p<=tree[rt<<1]) return update(p,lson);
else return update(p-tree[rt<<1],rson);
}
int main()
{
int i,n,k,&mod=tree[1];
while(scanf("%d%d",&n,&k)!=EOF){
for(i=1;i<=n;i++)scanf("%s%d",c[i].name,&c[i].val);
build(1,n,1);
int cnt=0;
while(cnt<35&&antiprime[cnt]<=n)cnt++;
cnt--;//求得该范围内的最大反质数factorNum[cnt]也即答案
int pos=0;c[pos].val=0;//因为要取mod所以标号从0开始
for(i=0;i<antiprime[cnt];i++){//只要玩到第答案个人也即最大值就行
if(c[pos].val>0)k=((k+c[pos].val-2)%mod+mod)%mod+1;//之所以在减是因为现在的人离开了要从前面一个人开始数
else k=((k+c[pos].val-1)%mod+mod)%mod+1;//标号从0开始所以要先-1再+1,和上面不同的是现在离开了答案就是对的
pos=update(k,1,n,1);
}
printf("%s %d\n",c[pos].name,factorNum[cnt]);
}
return 0;
}