题目链接: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;
}