题目链接:
POJ 2886 Who Gets the Most Candies?
题意 :
【懒得自己写了,直接抄网友的了o(╯□╰)o】
N个熊孩子围成一个圈,从第K个开始淘汰,每淘汰一个,出示手中的数字,决定下一个淘汰者,正数表示左手第n个,负数反之。每个人可以拿到的存活回数的因数个数的糖果,求拿到最多糖果数的孩子的名字以及糖果数。
分析:
先通过打表的方法得到每个区间里的拥有最大因子数的数字和相应的因子个数。
然后对每个输入n找到相应的区间,假设找到的拥有最大因子数的数字为time,那么只要模拟time次就行了。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define lson(x) (x<<1)
#define rson(x) ((x<<1)|1)
using namespace std;
const int maxn=500010;int n,k;
int val[maxn],Divisor_Num[40]={
0,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},Max_Num_Divisor[40]={
0,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,500050};
char name[maxn][15];struct SegTree{int left,right,num;
}segtree[maxn<<2];
/* inline int calc_divisor_num(int x) {int cnt=0,flag=0;for(int i=1;i*i<=x;i++){if(x%i==0) cnt++;if(i*i==x) flag=1;}return (2*cnt-flag); }inline void init() {for(int i=3;i<maxn;i++) Divisor_Num[i]=calc_divisor_num(i);for(int i=3;i<maxn;i++){if(Divisor_Num[i]>Divisor_Num[Max_Num_Divisor[i-1]]) Max_Num_Divisor[i]=i;else Max_Num_Divisor[i]=Max_Num_Divisor[i-1];} } */
inline void build(int left,int right,int cur)
{segtree[cur].left=left;segtree[cur].right=right;segtree[cur].num=right-left+1;if(left==right) return;int mid=(left+right)>>1;build(left,mid,lson(cur));build(mid+1,right,rson(cur));
}inline int query(int kk,int cur)
{int left=segtree[cur].left;int right=segtree[cur].right;if(left==right){segtree[cur].num=0;return left;}int tmp;if(kk<=segtree[lson(cur)].num) tmp=query(kk,lson(cur));else tmp=query(kk-segtree[lson(cur)].num,rson(cur));segtree[cur].num=segtree[lson(cur)].num+segtree[rson(cur)].num;return tmp;
}int main()
{//freopen("poj2886in.txt","r",stdin);//freopen("poj2886out.txt","w",stdout);/*init();printf("%d,",Max_Num_Divisor[1]);int cnt=1;for(int i=2;i<maxn;i++){if(Max_Num_Divisor[i]!=Max_Num_Divisor[i-1]){cnt++; printf("%d,",Max_Num_Divisor[i]);}if(cnt&&cnt%10==0){cnt=0;printf("\n");}}for(int i=1;i<=36;i++){printf("%d,",calc_divisor_num(Max_Num_Divisor[i]));}*/while(~scanf("%d%d",&n,&k)){build(1,n,1);for(int i=1;i<=n;i++){scanf("%s%d",name[i],&val[i]);}int time,ans;for(int i=1;i<40;i++){if(n>=Max_Num_Divisor[i]&&n<Max_Num_Divisor[i+1]){time=Max_Num_Divisor[i];ans=Divisor_Num[i];break;}}int left=n,id,tmp;for(int i=1;i<=time;i++){if(left==1) k=1;id=query(k,1);//查询剩余人数中的第k个人的编号//printf("i=%d id=%d ",i,id);if(i==time){printf("%s %d\n",name[id],ans);break;}left--,tmp=val[id];// printf("left=%d val[id]=%d ",left,val[id]);if(abs(val[id])>=left) val[id]=val[id]-val[id]/left*left;//printf("val[id]=%d pre_k=%d ",val[id],k);if(val[id]>0) {if(k+val[id]-1<=left) k=k+val[id]-1;else k=k+val[id]-1-left;} else if(val[id]==0){if(tmp>0) {if(k==1) k=left;else k--;}else if(k==left+1) k=1;//这个特判卡了好久好久!!!!!} else {if(k+val[id]>0) k=k+val[id];else k=left+k+val[id];}//printf("k=%d\n",k);}}return 0;
}