这道题又加深了我对线段树的认识,不过依然被自己坑的很惨,简直不能忍。
题意不难理解,用线段树来快速找到从当前开始的第k个人,注意公式推导一定要认真。最郁闷的是,自己的约数算法是错的。。。愚蠢的写成了i j都小于770,实际上有些数的约数可能大于根号500000.。。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAX=500010;
int table[MAX],n,k,val[MAX],segtree[MAX*4];
char name[MAX][20];
void push(int which){
segtree[which]=segtree[which<<1]+segtree[which<<1|1];
}
void build(int which,int front,int rear){
if(front==rear){
segtree[which]=1;
return ;
}
int mid=(front+rear)>>1;
build(which<<1,front,mid);
build(which<<1|1,mid+1,rear);
push(which);
}
int get(int num,int which,int front,int rear){
if(front==rear){
segtree[which]=0;
//printf("%db",front);
return front;
}
int ret,mid=(front+rear)>>1;
if(segtree[which<<1]>=num){
//printf("test");
ret=get(num,which<<1,front,mid);
}
else
ret=get(num-segtree[which<<1],which<<1|1,mid+1,rear);
push(which);
return ret;
}
int main(){
/*table[1]=1;
for(int i=2;i<MAX;i++)
table[i]=2;
for(int i=2;i<=770;i++)
for(int j=2;i*j<=MAX;j++){
if(i*j==1542)
printf("%d %d\n",i,j);
table[i*j]++;
}*/
int limit=(int)sqrt(MAX*1.0);
for(int i=1; i<=limit; ++i)
{
for(int j=i+1; j*i<=MAX; ++j)
table[i*j]+=2;
table[i*i]++;
}
//for(int i=1;i<10000;i++)
//printf("%d\n",table[1542]);
int maxx;
char names[20];
while(scanf("%d %d",&n,&k)!=EOF){
build(1,1,n);
int left=n-1;
maxx=0;
for(int i=1;i<=n;i++){
scanf("%s %d",name[i],&val[i]);
}
/*if(k>0){这部分不需要考虑
if(k%n!=0)
k%=n;
else
k=n;
}
else{
if(k%n!=0){
k%=n;
}
else
k=-n;
k+=n+1;
}*/
for(int i=1;i<=n;i++){
int num=get(k,1,1,n);
//printf("%d ",num);
if(table[i]>maxx){
maxx=table[i];
strcpy(names,name[num]);
}
if(i==n)//i等于n时会发生对0取余的错误
break;
if(val[num]>0){
k=k+val[num]-1;
if(k%left!=0)
k%=left;
else
k=left;
}
else{
int help=left-k+1-val[num];
if(help%left!=0)
help%=left;
else
help=left;
k=left-help+1;
}
//printf("k%d",k);
left--;
//printf("a");
}
printf("%s %d\n",names,maxx);
}
return 0;
}