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

本文介绍了一种关于球圈操作的算法问题,旨在通过不同数据结构(如线段树、树状数组及set集合)来寻找使球按指定顺序出圈所需的最小时间。通过对比分析,得出线段树在解决此类问题时更为高效。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

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

解:

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

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

/*
Pro: 0

Sol:

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 | 1
using 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: 0

Sol:

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 | 1
using 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 100100
int 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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值