http://poj.org/problem?id=2886
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define maxn 500100 5 using namespace std; 6 7 typedef long long ll; 8 const int prime[16]= {1,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47}; 9 int n,k; 10 struct node 11 { 12 int l,r,num; 13 } tree[maxn*3]; 14 15 ll maxsum,bestnum; 16 char name[maxn][110]; 17 int a[maxn]; 18 19 void getantiprime(ll num, ll k,ll sum,int limit) 20 { 21 //num:当前枚举到的数,k:枚举到的第k大的质因子;sum:该数的约数个数;limit:质因子个数上限; 22 int i; 23 ll temp; 24 if(sum > maxsum) 25 { 26 maxsum = sum; 27 bestnum = num; //如果约数个数更多,将最优解更新为当前数; 28 } 29 if(sum==maxsum && bestnum > num) 30 bestnum = num; //如果约数个数相同,将最优解更新为较小的数; 31 if(k > 15) 32 return; 33 temp = num; 34 for(i=1; i<=limit; i++) //开始枚举每个质因子的个数; 35 { 36 if(temp*prime[k] > n) 37 break; 38 temp = temp * prime[k]; //累乘到当前数; 39 getantiprime(temp, k+1, sum*(i+1), i); //继续下一步搜索; 40 } 41 } 42 43 void build(int i,int l,int r)//建树 44 { 45 tree[i].num=r-l+1; 46 tree[i].l=l; 47 tree[i].r=r; 48 if(l<r) 49 { 50 int mid=(l+r)/2; 51 build(i+i,l,mid); 52 build(i+i+1,mid+1,r); 53 } 54 } 55 56 int search1(int num,int i)//查找原始序号 57 { 58 tree[i].num--; 59 if(tree[i].l==tree[i].r) 60 { 61 return tree[i].l; 62 } 63 if(num<=tree[i+i].num) 64 return search1(num,i+i); 65 return search1(num-tree[i+i].num,i+i+1); 66 } 67 68 int main() 69 { 70 while(scanf("%d%d",&n,&k)!=EOF) 71 { 72 getantiprime(1,1,1,50);//找到n以内反素数最大的; 73 build(1,1,n); 74 for(int i=1; i<=n; i++) 75 { 76 scanf("%s %d",name[i],&a[i]); 77 } 78 int id; 79 for(int i=0; i<bestnum; i++)//约瑟夫原理 80 { 81 n--; 82 id=search1(k,1); 83 if(n==0) break; 84 if(a[id]>0) 85 k=(k-1+a[id]-1)%n+1; 86 else 87 k=((k-1+a[id])%n+n)%n+1; 88 } 89 printf("%s %lld\n",name[id],maxsum); 90 } 91 return 0; 92 }