POJ 2886 Who Gets the Most Candies?

来源:互联网 发布:linux vi 移动到行尾 编辑:程序博客网 时间:2024/04/30 02:19

题目链接:http://poj.org/problem?id=2886


题目大意:每次选一个人出圈,若选到第i个人,则下一次选接下来第s[i]个人,每个人得到第几个出圈的序数i的约数个数个糖果,问谁得到的糖果最多。


反素数:设i的素数个数为g(i),对于n有任意的i<n,有g(i)<g(n)

所以我们只需找到给定的n内最大的反素数(可耻的打表了)

对于反素数的问题。。。以后再说吧

然后是确定每次谁出列,假设当前出列的k,则下次出列的是k是第几个+s[k],这里采用迭代计算,也就是k是第几个在上次会算出,只需再加上s[k]即可,

假设现在需要找第k个,用线段树或者树状数组求前缀和,每次将出圈的人的值-1,二分找到当前的人,注意的是找到的可能已经出圈,需要向前找第一个未出圈的人


代码如下:

#include<cstdio>#include<cstring>using namespace std;const int a[40] = {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,500001};  const int b[40] = {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,0};  char name[500005][15];int d[500005];int s[500005];int c[500005];bool f[500005];int n,k;int l,r,mid;int now;int t;int ans;int lowbit(int x){return x&(-x);}void change(int x,int y){for (;x<=n;x+=lowbit(x)){c[x]+=y;}}int getsum(int x){int sum=0;for (;x;x-=lowbit(x)){sum+=c[x];}return sum;}int main(){while (scanf("%d%d",&n,&k)!=EOF){memset(c,0,sizeof(c));memset(f,0,sizeof(f));for (int i=1;i<=n;i++){getchar();scanf("%s%d",name[i],&s[i]);change(i,1);}ans=0;while (a[ans]<=n){ans++;}ans--;t=k;for (int i=1;i<a[ans];i++){change(k,-1);f[k]=1;if (s[k]>0){t+=s[k]-1;}else{t+=s[k];}t%=(n-i);while (t<0){t+=n-i;}if (t==0){t=n-i;}l=1;while (f[l]){l++;}r=n;while (f[r]){r--;}while (r>=l){mid=(l+r)>>1;now=getsum(mid);if (now==t){k=mid;break;}else{if (now>t){r=mid-1;}else{l=mid+1;}}}while (f[k]){k--;}}printf("%s %d\n",name[k],b[ans]);}return 0;} 


0 0
原创粉丝点击