/*
线段树
需要用到求一个数的约数个数,这个需要打个表吧
此处的表,是借用了别人。因为我只是想学习下线段树,偷懒了下
这线段树,其实也没什么特别的,重要的是如何构造线段树的保存的值。就想网络流,二分匹配的算法似的
本身没什么特别的,但是构图很重要,比算法本身重要
*/
// include file
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <ctime>
#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <bitset>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <set>
#include <list>
#include <functional>
using namespace std;
// typedef
typedef long long LL;
typedef unsigned long long ULL;
//
#define read freopen("in.txt","r",stdin)
#define write freopen("out.txt","w",stdout)
#define Z(a) (a<<1)
#define Y(a) (a>>1)
const double eps = 1e-6;
const double INFf = 1e100;
const int INFi = 1000000000;
const LL INFll = (LL)1<<62;
const double Pi = acos(-1.0);
template<class T> inline T sqr(T a){return a*a;}
template<class T> inline T TMAX(T x,T y)
{
if(x>y) return x;
return y;
}
template<class T> inline T TMIN(T x,T y)
{
if(x<y) return x;
return y;
}
template<class T> inline T MMAX(T x,T y,T z)
{
return TMAX(TMAX(x,y),z);
}
template<class T> inline T MMIN(T x,T y,T z)
{
return TMIN(TMIN(x,y),z);
}
template<class T> inline void SWAP(T &x,T &y)
{
T t = x;
x = y;
y = t;
}
// code begin
struct node
{
char name[12];
int card;
};
node data[500010];
struct seg_tree_node
{
int left,right; // 左右编号
int remain;
};
seg_tree_node mem[1050010];
int N,K;
void buildSegtree(int l,int r,int dx=1)
{
mem[dx].left = l;
mem[dx].right = r;
mem[dx].remain = r-l+1;
//printf("%d\n",dx);
if(l==r) return;
buildSegtree(l,Y(l+r),Z(dx));
buildSegtree(Y(l+r)+1,r,Z(dx)+1);
}
int query(int pos,int dx=1) //第pos位置小孩要出局了,那么要更新局面了
{
if(mem[dx].left==mem[dx].right)
{
--mem[dx].remain;
return mem[dx].left;
}
int zson = Z(dx),yson =Z(dx)+1;
int left = mem[zson].remain;
int right = mem[yson].remain;
--mem[dx].remain;
if(pos>left)
{
return query(pos-left,yson);
}
else
{
return query(pos,zson);
}
}
const int PV[40] = {1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,1260,1680,2520,5040,7560,10080,15120,20160,25200,27720,45360,50400,55440,83160,110880,166320, 221760, 277200, 332640, 498960, 554400, 665280};
const int Nu[40] = {1, 2, 3, 4, 6, 8, 9, 10, 12, 16, 18, 20, 24, 30, 32, 36, 40, 48, 60, 64, 72, 80, 84, 90, 96, 100, 108, 120, 128, 144, 160, 168, 180, 192, 200, 216, 224};
int main()
{
int pre,findit,ans[2];
read;
write;
while(scanf("%d %d",&N,&K)==2)
{
//getchar();
for(int i=0;i<N;i++)
{
//gets(in);
scanf("%s %d",data[i].name,&data[i].card);
}
buildSegtree(0,N-1);
pre = K;
for(int i=0;i<40;i++)
{
if(PV[i]>N) break;
ans[0] = PV[i];
ans[1] = Nu[i];
}
for(int i=1;i<=N;i++) //总共循环N次,最后一次找到的就是那个孩子的编号了。
{
//之前的是找到第pre个小孩子
findit = query(pre); // 然后在最新的情况下找下个的坐标
//printf("找到的下标编号: %d %d\n",pre,findit);
if(i==ans[0])
{
ans[0] = findit;
break;
}
if(i==N) break;
//根据findit找一下个pre
if( data[findit].card>0 )
{
pre = (pre-1+(data[findit].card-1)%(N-i))%(N-i)+1;
}
else
{
pre = (pre-1+N-i+(data[findit].card)%(N-i) )%(N-i)+1; //这里出现问题
}
}
printf("%s %d\n",data[ans[0]].name,ans[1]);
}
return 0;
}
转载于:https://www.cnblogs.com/ac2012/archive/2011/04/13/2015499.html