题目地址: http://poj.org/problem?id=2886
一开始翻译搓了。。。 囧。。。 F(p) is the number of positive integers that perfectly divide p. 这句话是求p的因子个数。。。。
那么首先,需要把所有数的因子个数预处理。。。
这里就需要运用到一个数论的知识(反素数?)。。。
大家都知道,除了1以外的每个数都可以分解成若干个质数相乘而得:
n=p1^n1*p2^n2*p3^n3...pk^nk;
(p1等表示质数,n1等表示质数个数,n表示被分解的数)
然后我们就可以得到:
n的所有因子的个数就是(n1+1)*(n2+1)...(nk+1)
OK,接下去就是建立树状数组,每次操作从树状数组中减去当前跳出的这个人,查找下一个jump out的童鞋时,利用寻找第k大的方法得到其坐标。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 500010
int maxans[maxn],maxid[maxn],ans[maxn];
bool flag[maxn];
void deal(){
int i,j,tmp,num;
for(i=1;i<=maxn;i++)
ans[i]=1;
for(i=2;i<=maxn;i++){
if(flag[i]) continue;
for(j=i+i;j<=maxn;j+=i){
num=1;
tmp=j;
while(tmp%i==0){
tmp/=i;
num++;
}
ans[j]*=num;
flag[j]=true;
}
}
maxans[1]=maxid[1]=1;
for(i=2;i<=maxn;i++){
if(ans[i]>maxans[i-1])
maxans[i]=ans[i],maxid[i]=i;
else maxans[i]=maxans[i-1],maxid[i]=maxid[i-1];
}
}
int tree[maxn],s[maxn],dir[maxn];
char str[maxn][11];
int n;
void add(int v,int val){
while(v<=n){
tree[v]+=val;
v+=v&-v;
}
}
int query(int v){
int sum=0;
while(v>0){
sum+=tree[v];
v-=v&-v;
}
return sum;
}
int findk( int k ){ // 二分法寻找第k大
int now=0;
for( int i=20; i>=0 ; i-- ) {
now|=(1<<i);
if(now>= n || tree[now]>=k)
now^=(1<<i);
else k-=tree[now];
}
return now+1;
}
int main(){
int i,j,k,l,r,mid,now,maxk,step,tmp;
deal();
while(~scanf("%d%d",&n,&k)){
for(i=1;i<=n;i++)
scanf("%s%d",str[i],&s[i]);
for(i=1;i<=n;i++)
tree[i]=0;
for(i=1;i<=n;i++)
add(i,1);
dir[step=1]=maxk=now=k;
while(step<n){
r=n-step;
if(s[now]>0)
maxk=(maxk-1+s[now])%r;
else
maxk=(maxk+s[now])%r;
if(maxk<1) maxk+=r;
add(now,-1);
now=findk(maxk);
dir[++step]=now;
}
printf("%s %d\n",str[dir[maxid[n]]],maxans[n]);
}
return 0;
}