hdu 4262 Juggler 这题真是跟小丑一般。。。

来源:互联网 发布:java默认的编码方式 编辑:程序博客网 时间:2024/04/27 20:02

题意:

       有个球的圈圈。三种操作:逆时针转一个,顺时针转一个,丢掉手中的那个的同时顺时针的球到你的手里。每个操作都花费一秒。告诉你要求的出圈顺序,求最小花费时间。注:开始在手中的球为1.

解:

      线段树和树状数组都可。树状数组很蛋疼。建议我以后用线段树。开始为什么不用线段树是因为怕自己搞不出相对坐标和绝对坐标。凡是二分的树状数组能不写就不写。

这个是用set代替二分的代码,建议以后迫不得已要用二分的时候就用set。

/*Pro: 0Sol:date:*/#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>#include <queue>#include <set>#include <vector>#define maxn 100010#define lson l, m, rt << 1#define rson m + 1, r, rt << 1 | 1#define ls rt << 1#define rs rt << 1 | 1using namespace std;int n,now,c[maxn],pre,suf,alre,out,in;__int64 ans;struct query{    int id, ord;}q[maxn];bool cmpx(query a,query b){    return a.ord < b.ord;//ord是时间}int getsum(int pos){    int sum = 0;    while(pos){        sum += c[pos];        pos -= (pos & -pos);    }return sum;}void modify(int pos){    while(pos <= n){        c[pos] += 1;        pos += (pos & -pos);    }}set <int> S;set <int> :: iterator it;int main(){    while(~scanf("%d",&n) && n){        memset(c,0,sizeof(c));//0 表示在手里, 1 表示已经出去了  id建边        S.clear();        for(int i = 1; i <= n; i ++){            scanf("%d",&q[i].ord);            q[i].id = i;            S.insert(i);        }        sort(q + 1, q + n + 1, cmpx); now = 1;   ans = 0;    alre = 0;        for(int i = 1; i <= n; i ++){          //  cout<<now<<" "<<q[i].id<<endl;            if(now > q[i].id) {                pre = q[i].id;                suf = now;            }else{                pre = now;                suf = q[i].id;            }            pre = pre  - getsum(pre);//表示前面有多少个0,多少个还在,包括本身            suf = suf - getsum(suf);            in = suf - pre;            out = n - alre - in;            ans+=min(in,out)+1;            alre ++;            if(alre==n)break;            S.erase(q[i].id);            if(S.lower_bound(q[i].id)!=S.end())            {                it=S.lower_bound(q[i].id);            }            else            {                it=S.lower_bound(0);            }            now = *it ;        }        cout<<ans<<endl;    }return 0;}
这个是改出来的二分。老娘虚脱了。

/*Pro: 0Sol:date:*/#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>#include <queue>#include <set>#include <vector>#define maxn 100010#define lson l, m, rt << 1#define rson m + 1, r, rt << 1 | 1#define ls rt << 1#define rs rt << 1 | 1using namespace std;int n,now,c[maxn],pre,suf,alre,out,in;__int64 ans;struct query{    int id, ord;}q[maxn];bool cmpx(query a,query b){    return a.ord < b.ord;//ord是时间}int getsum(int pos){    int sum = 0;    while(pos){        sum += c[pos];        pos -= (pos & -pos);    }return sum;}void modify(int pos){    while(pos <= n){        c[pos] += 1;        pos += (pos & -pos);    }}int bs(int l,int r){    int mid,flag=l;    while(l + 1< r)    {        mid=(l+r)>>1;        if(getsum(mid)-getsum(l)==mid-l)        {            l=mid;        }        else        {            r=mid;        }    }    if(getsum(l)-getsum(flag)==l-flag)    {        return r;    }    return l;}int main(){    while(~scanf("%d",&n) && n){        memset(c,0,sizeof(c));//0 表示在手里, 1 表示已经出去了  id建边        for(int i = 1; i <= n; i ++){            scanf("%d",&q[i].ord);            q[i].id = i;        }        sort(q + 1, q + n + 1, cmpx); now = 1;   ans = 0;    alre = 0;        for(int i = 1; i <= n; i ++){            if(now > q[i].id) {                pre = q[i].id;                suf = now;            }else{                pre = now;                suf = q[i].id;            }            pre = pre  - getsum(pre);//表示前面有多少个0,多少个还在,包括本身            suf = suf - getsum(suf);            in = suf - pre;            out = n - alre - in;            ans+=min(in,out)+1;            alre ++;            if(alre==n)break;            modify(q[i].id);            if(getsum(n)-getsum(q[i].id)==n-q[i].id)            {               now= bs(0,q[i].id);//边界值问题需要处理一下            }            else            {               now= bs(q[i].id,n);            }        }        cout<<ans<<endl;    }return 0;}

线段树代码: 其实我写过一遍类似的poj 2886,当时就是照着别人的代码敲的,还以为自己会了呢,但是发觉理解得还是不够深啊。。。别人的和自己的就是不一样啊。要把别人的学到手!!!

#include <cstdio>#include <algorithm>using namespace std;#define lson l,m,rt << 1#define rson m + 1 , r, rt <<1 | 1#define havem int m = (l + r) >> 1#define ls rt << 1#define rs rt << 1 | 1#define maxn 100100int sum[maxn << 2];void build(int l, int r, int rt){    if(l == r){        sum[rt] = 1;        return ;    }havem;    build(lson); build(rson);    sum[rt] = sum[ls] + sum[rs];}void update(int pos, int l, int r, int rt){    if(l == r){        sum[rt] = 0;        return ;    }havem;    if(pos <= m)    update(pos,lson);    else update(pos,rson);    sum[rt] = sum[ls] + sum[rs];}int query(int L,int R, int l, int r, int rt){    if(L <= l && r <= R){        return sum[rt];    }havem;    int ans = 0;    if(L <= m ) ans = query(L,R,lson);    if(R > m) ans += query(L,R,rson);    return ans;}struct Qu{    int id,time;    bool operator < (const Qu& cmp)const{        return time < cmp.time;    }}q[maxn];int getpos(int pos, int l, int r, int rt){//去找从1开始的第pos个人,如果pos这个地方就有人,那么就是他了    if(l == r) return l;    havem;    if(pos <= sum[ls])        return getpos(pos,lson);    return getpos(pos - sum[ls],rson);}int n;int main(){    while(~scanf("%d",&n) && n){        build(1,n,1);        for(int i = 1; i <= n; i ++){            scanf("%d",&q[i].time);            q[i].id = i;        }        sort(q + 1, q + 1 + n);        int& mod = sum[1];//        int now = 1;        __int64 ans = 0;        for(int i = 1; i <= n; i ++){            int tmp;            if(now == q[i].id){                ans += 1;            }else if(now < q[i].id){                tmp = query(now + 1,q[i].id,1,n,1);                ans += min(tmp,mod - tmp) + 1;            }else{                tmp = query(q[i].id,now - 1,1,n,1);                ans += min(tmp,mod - tmp) + 1;            }            update(q[i].id,1,n,1);            int Left = query(1,q[i].id,1,n,1);            if( Left < mod ){                //左边小于剩下的人数,说明右边有人,就去右边找                now = getpos(Left + 1,1,n,1);//去找剩下的Left+1个人            }else{                //从后面找第一个1                now = getpos(1,1, n, 1);            }        }        printf("%I64d\n",ans);    }    return 0;}



原创粉丝点击