• HDU4262–Juggler(区间求和&&单点更新)


    题目大意

    有一个圆形管道,里面有N个球,给定N个球的出圈顺序,最初的时候手的位置是在第一个球的位置,如果一个球的位置刚好是手所在的位置,那么它可以被取出,要求你按照给定的出圈顺序,依次取出N个球,在旋转到目标小球的时候,可以向左旋转,也可以向右旋转,每移动一个单位位置,需要一个单位的花费,要求你计算出最少的花费是多少

    题解

    如果读懂题目了,那么就很好做了,当时模拟的比赛的时候看了好久题目都没有看懂题,o(╯□╰)o。。。对于每一个位置,用1来表示有球,0来表示没求,用线段树来维护前缀和即可,每次查找手所在位置之前有多少个球,然后查找目标小球的位置之前有多少个球,这两个操作都是求前缀和,两个值的差的绝对值就是它们两之间的一个距离d,假设当前处理的是第i个球,那么另外一个距离等于:n-i+1-d。选择两者中的小者。然后进行删除操作(单点更新)

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define MAXN 100005
    #define lson l,m,s<<1
    #define rson m+1,r,s<<1|1
    int sumv[MAXN<<2],pos[MAXN];
    void PushUp(int s)
    {
        sumv[s]=sumv[s<<1]+sumv[s<<1|1];
    }
    void build(int l,int r,int s)
    {
        if(l==r) {
            sumv[s]=1;
            return;
        }
        int m=(l+r)>>1;
        build(lson);
        build(rson);
        PushUp(s);
    }
    void update(int p,int l,int r,int s)
    {
        sumv[s]--;
        if(l==r) return;
        int m=(l+r)>>1;
        if(p<=m) update(p,lson);
        else
            update(p,rson);
    }
    int query(int ql,int qr,int l,int r,int s)
    {
        if(ql<=l&&r<=qr)
            return sumv[s];
        int m=(l+r)>>1,ans=0;
        if(ql<=m) ans+=query(ql,qr,lson);
        if(qr>m) ans+=query(ql,qr,rson);
        return ans;
    }
    int main(void)
    {
        int n,p,a,b,d;
        while(scanf("%d",&n)!=EOF&&n) {
            __int64 sum=0;
            build(1,n,1);
            for(int i=1; i<=n; i++) {
                scanf("%d",&p);
                pos[p]=i;
            }
            p=1;
            for(int i=1; i<=n; i++) {
                a=0;
                b=0;
                if(p-1) a=query(1,p-1,1,n,1);
                if(pos[i]-1) b=query(1,pos[i]-1,1,n,1);
                d=abs(a-b);
                sum+=min(d+1,n-i+2-d);
                update(pos[i],1,n,1);
                p=pos[i];
            }
            printf("%I64d\n",sum);
        }
        return 0;
    }

    上述方法耗时1156ms,由于题目要求的操作就是查询前缀和以及单点修改,因此可以用树状数组来做,空间消耗和时间消耗都要比用线段树小,耗时只需要390ms

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define MAXN 100005
    int c[MAXN],pos[MAXN];
    int n;
    int lowbit(int x)
    {
        return x&-x;
    }
    void add(int x,int d)
    {
        while(x<=MAXN) {
            c[x]+=d;
            x+=lowbit(x);
        }
    }
    int sum(int x)
    {
        int ret=0;
        while(x>0) {
            ret+=c[x];
            x-=lowbit(x);
        }
        return ret;
    }
    int main(void)
    {
        int a,b,d,p;
        while(scanf("%d",&n)!=EOF&&n) {
            __int64 ans=0;
            memset(c,0,sizeof(c));
            for(int i=1; i<=n; i++) {
                scanf("%d",&p);
                pos[p]=i;
                add(i,1);
            }
            int p=1;
            for(int i=1; i<=n; i++) {
                a=sum(p-1);
                b=sum(pos[i]-1);
                d=abs(a-b);
                ans+=min(d+1,n-i+2-d);
                add(pos[i],-1);
                p=pos[i];
            }
            printf("%I64d\n",ans);
        }
    }
     
  • 相关阅读:
    android讲义2之自定义view
    android讲义2之单项选择
    android讲义2之计时器组件Chronometer
    android讲义2之代码布局
    android讲义2之图片变换
    android讲义2之简单图片浏览器且有截图效果(对ImageView使用)
    android讲义2的相对布局(持续更新)
    android讲义2之在xml中设定imageButtion
    MoSH——移动设备上的Shell
    ArithmeticOperators.cs
  • 原文地址:https://www.cnblogs.com/zjbztianya/p/3092121.html
Copyright © 2020-2023  润新知