标签:
约瑟夫问题的升级版,每次出去的是前一个出去的人位置+手上的数字(正往前,负往后)。第i个出去的人拿的糖是i的约数的个数。求拿糖最多的人和他的糖果数。
线段树单点更新,反素数。
我竟然WA在了反素数少了几个QAQ
#include<cstdio> #include<cstring> #define N 500002 #define mid int m=l+((r-l)>>1) #define lson l,m,node<<1 #define rson m+1,r,node<<1|1 using namespace std; int v[N]; char name[N][13]; int n,k; int sum[N<<2]; int rprim[50]= {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 nprim[50]= {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 node) { sum[node]=r-l+1;//sum储存这个区间有多少个数 if(l<r) { mid; build(lson); build(rson); } } int out(int l,int r,int node,int k) { sum[node]--;//这个区间减少一个数 if(l==r) return l;//返回这个减少的数的原始下标 mid; if(k<=sum[node<<1])//要找的第k个数小于等于左半区间的个数 return out(lson,k);//就递归左子树 else return out(rson,k-sum[node<<1]);//否则就在右子树,且k-左子树的个数 } int main() { while(~scanf("%d%d",&n,&k)) { memset(name,0,sizeof(name));//清空名字 for(int i=1; i<=n; i++) scanf("%s%d",name[i],&v[i]); build(1,n,1); int tn=n,now,p=0; while(rprim[p]<=n)p++;//找出n里最大的反素数 for(int i=1; i<rprim[p-1]; i++)//反素数前的都出队 { now=out(1,n,1,k);//当前出队的序号 tn--;//剩下的人数 if (v[now]>0)//向前数 k=(k-1+v[now])%tn;//先减去本身这个位置 然后往前v个 再取模 else k=((k+v[now])%tn+tn)%tn;//直接往后 然后要取模再取模保证正数 if (k==0) k=tn;//如果刚好是tn 取模会变成0 } now=out(1,n,1,k);//得到第最大的反素数个出队的人的序号 printf("%s %d\n",name[now],nprim[p-1]); } return 0; }
【POJ 2886】Who Gets the Most Candies?
标签:
原文地址:http://www.cnblogs.com/flipped/p/5202584.html