这题有一个很好的数学类解法。推导出母函数来直接求解,很高效。这边介绍一种更为普遍的模拟方法,用树状数组来模拟约瑟夫问题。
本题先预处理出要求的素数。然后每次新形成的环里下一个目标的间隔就是相应的素数。
在这里用树状数组来处理元素动态删除和在线统计间隔以快速确定下一个元素下标,这里用二分来逼近。
本题先预处理出要求的素数。然后每次新形成的环里下一个目标的间隔就是相应的素数。
在这里用树状数组来处理元素动态删除和在线统计间隔以快速确定下一个元素下标,这里用二分来逼近。
动态删除即将单点更新为-1,统计直接取和。
#include <stdio.h>
#include <vector>
#include <iostream>
#include <cstring>
using namespace std;
const int maxn=3502;
bool use[40000];
int p[maxn],ans[maxn],c[maxn];
inline int lowbit(int x)
{
return x&(-x);
}
void update(int x,int p)
{
for(int i=x; i<maxn; i+=lowbit(i))
c[i]+=p;
}
int sum(int x)
{
int ans=0;
for(int i=x; i>0; i-=lowbit(i))
ans+=c[i];
return ans;
}
void init()
{
int t=0;
memset(use,false,sizeof(use));
p[t++]=2;
for(int i=3; i<40000; i+=2)
if(!use[i])
{
p[t++]=i;
for(int j=i*2; j<40000; j+=i)
use[j]=true;
}
}
void binary(int n,int k)
{
int l=1,r=n,mid;
while(l<=r)
{
mid=(l+r)>>1;
if(sum(mid)<k) l=mid+1;
else r=mid-1;
}
update(l,-1);
}
int main()
{
init();
int nn,t;
for(int n=1; n<=maxn; n++)
{
nn=n,t=1;
for(int i=1;i<=n;i++) c[i]=0;
for(int i=1; i<=n; i++) update(i,1);
for(int i=0; i<n-1; i++)
{
t=(t+p[i]-2)%nn+1;//原本t=(t+p[i]-1)%nn,由于下标从1开始,方便处理,同加1
binary(n,t);
nn--;
if(nn==0) break;
}
for(int i=1; i<=n; i++)
{
if(c[i])
{
ans[n]=i;
break;
}
}
}
int x;
while(scanf("%d",&x)==1&&x)
printf("%d\n",ans[x]);
return 0;
}
#include <stdio.h>
#include <cstring>
const int maxn=100001;
int c[maxn],a[maxn],ans[maxn];
inline int lowbit(int x)
{
return x&(-x);
}
inline void update(int x,int p)
{
for(int i=x; i<maxn; i+=lowbit(i))
c[i]+=p;
}
inline int sum(int x)
{
int ans=0;
for(int i=x; i>0; i-=lowbit(i))
ans+=c[i];
return ans;
}
int binary(int n,int k)
{
int l=1,r=n,mid;
while(l<=r)
{
mid=(l+r)>>1;
if(sum(mid)<k) l=mid+1;
else r=mid-1;
}
return l;
}
int main()
{
int n;
while(scanf("%d",&n)==1&&n)
{
memset(c,0,sizeof(c));
for(int i=1; i<=n; i++) scanf("%d",&a[i]),update(i,1);
int res=n,t=1;
for(int i=1; i<=n; i++)
{
t=(t+a[i]-2)%res+1;
int temp=binary(n,t);
ans[i]=temp;
update(temp,-1);
res--;
if(res==0) break;
}
for(int i=1; i<n; i++)
printf("%d ",ans[i]);
printf("%d\n",ans[n]);
}
return 0;
}