poj 2886(线段树单点更新)

来源:互联网 发布:seo经验分享 编辑:程序博客网 时间:2024/05/01 21:31

poj 2886


题意:

有N个人,顺时针围成一个圈,现指定第K个人先跳出,然后报一个数A,A>0,表示从跳出的人(跳出的人不算)左边第一个人开始的第A个人跳出,A<0,则相反,且之后跳出的人进行相同的步奏,现要求的是第i个人跳出时,满足当前i的因子数最多且因子数一样时越早跳出越好。


解题思路:

首先我们可以算出当前如果有N个人它的反素数(<=N,且因子数最多并且最小),然后当一个人跳出时,我们可以算出这个人得左和右各有多少人,这样我们可以求出当前为A时,下一个人在当前总人数的倒数第几个,然后利用线段树去找对应的位置,并更新即可。

注意:

反素数可以利用dfs求

网站:点击打开链接

#include <stdio.h>#include <string.h>#include <math.h>#include <stdlib.h>typedef int  int64;#define MAXN0 500010#define l1(x) (x<<1)#define l2(x) (l1(x)+1)#define r1(x) ((x)>>1)char na[MAXN0][15];int way[MAXN0],cnt,p[800];bool vis[800];int ans,cnter;struct yznode{    int num,yz;};yznode yzmax[MAXN0];struct node{    int L,R,C;    void setLRC(int aa,int bb){        L = aa;        R = bb;        // C = cc;    }};node TR[MAXN0<<2];int64 prime[16]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47};void dfs(int64 cur,int64 cnt,int64 power,int64 sub,int n){    int64 i;    if(cur>n)        return;    if(cnt==cnter&&cur<ans)        ans=cur;    if(cnt>cnter)    {        ans=cur;        cnter=cnt;    }    int64 p=prime[sub];    for(i=1;i<=power;i++)    {        if(cur*p>n)            break;        dfs(cur*p,cnt*(i+1),i,sub+1,n);        p=p*prime[sub];    }}void buildTR(int ind,int L,int R){    TR[ind].setLRC(L, R);    if(L==R){        TR[ind].C = 1;        return;    }    int mid = r1(L+R);    int ind1 = l1(ind);    int ind2 = ind1+1;    buildTR(ind1, L, mid);    buildTR(ind2, mid+1, R);    TR[ind].C = TR[ind1].C+TR[ind2].C;}void pushup(int ind,int ind1,int ind2){    TR[ind].C = TR[(ind1)].C+TR[(ind2)].C;}//int update(int ind,int K){//    if(TR[ind].L==TR[ind].R){//        if(TR[ind].L==K){//            TR[ind].C = 0;//        }//        return 0;//    }//    int mid = r1(TR[ind].L+TR[ind].R),H=0;//    if(mid>=K){//         H = update(l1(ind),K) + TR[l2(ind)].C;//       // pushup(ind);//    }//    else {//         H =   update(l2(ind), K);////    }//    pushup(ind);//    return H;//}int Query(int ind,int F){    if(TR[ind].L==TR[ind].R){        // TR[ind].C = 0;        TR[ind].C = 0;        return TR[ind].L;                //return 0;    }    int H;    int ind1,ind2;    ind1 = (l1(ind));    ind2 = (ind1+1);    if(TR[ind2].C>=F){                H =   Query(ind2,F);    }    else {        H =  Query(ind1,F - TR[ind2].C);    }    pushup(ind,ind1,ind2);    return H;}void solve(int N,int K){    int ind = ans;    //int nn = yzmax[N].num;    //int cnt = 0;    int tmpN = N;    int tmp0,tmp1,tmp2,tmp3,tmp4,tmp8;    int cc = 1;    --tmpN;    //tmp0  = Query(1,N-K+1);//当前在K右边的总数    //tmp1 = tmpN - tmp0;    if(N!=1){        Query(1, N-K+1);        tmp0 = N - K ;        tmp1 = K - 1;    }    while(cc<ind){        tmp8 = abs(way[K])%tmpN;        if(!tmp8)tmp8+=tmpN;        if(way[K]<0){            if(tmp0==0||tmp1==0){                tmp4 = tmp8;            }            else{                if(tmp8<=tmp1){                    tmp4 = tmp0 + tmp8;                }                else {                    tmp4 = tmp8 - tmp1;                }            }        }        else {            if(tmp0==0||tmp1==0){                tmp4 = tmpN - tmp8 + 1;            }            else{                if(tmp8<=tmp0){                    tmp4 = tmp0 - tmp8 + 1;                }                else {                    tmp4 = tmpN + tmp0 - tmp8 + 1 ;                }            }        }        K = Query(1,tmp4);        --tmpN;        //int tmp6 = tmp0;        tmp0 = tmp4 -1;        tmp1 = tmpN - tmp0;        ++cc;    }    printf("%s %d\n",na[K],cnter);}int main(){    int N,K;    //getpr();    //prepro();    while(scanf("%d%d",&N,&K)!=EOF){        buildTR(1,1,N);        for(int i=1;i<=N;++i){            scanf("%s%d",na[i],&way[i]);        }        cnter = 0,ans = 0;        dfs(1,1,50,0,N);        solve(N,K);        //}    }    return 0;}


0 0
原创粉丝点击