題目地址: 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 500010int 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;elsemaxk=(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;}