2018.5.30 T1 业火的向日葵(sun.cpp/c/pas)

题目背景Background

只是有一天,qiancl 看到一道题,发现不会(:зゝ∠),后来发现这道题化简一下可以拿来出题,题
目名字是乱打的,不要太在意

题目描述Description

梵高是个有事没事上厕所也画向日葵的家伙,某天他到街上卖他的向日葵,得到了N 枚硬币,他把
这些硬币叠成了M 堆,现在要解决的问题如下:
(I) 每个硬币都长的一模一样,但是面值不同
(II) 梵高有强迫症,他打算把这些硬币按面值从大到小用完
(III)你可以把任意一堆中位于顶端的硬币移动到其他某堆的顶端,若你移动的该枚硬币是当前所有硬
币中面值最大的,梵高会直接把他用掉
(IV)求出用掉所有硬币最少需要的步数,直接用掉不计入步数
(V) 由于出题人很良心,上面这个问题比较难,这里你只要解决下面这个较简单的版本:
硬币面值两两不同,且M=2

输入描述(sun.in) Input Description

第一行两个正整数n1,n2,分别表示两堆硬币的个数
接下来n1 个整数按从顶到底的顺序排列,表示第一堆硬币的面值
接下来n2 个整数按从顶到底的顺序排列,表示第二堆硬币的面值

输出描述(sun.out) Output Description

一行一个整数表示最少步数

样例输入Sample Input

3 3
1 4 5
2 7 3

样例输出Sample Output

6

数据范围及提示Data Size & Hint

对于20%的数据,有1<=n1+n2<=100
对于40%的数据,有1<=n1+n2<=1000
对于100%的数据,有1<=n1+n2<=100000


此次唯一有趣的题目
这里写图片描述
将读入按照图储存,就变成了移动中间的一条线,每次答案加上移动的距离,减去中间已经取走的硬币个数,这可以用树状数组维护

#include <cstdio>
#include <algorithm>
using namespace std;
#define int long long
const int N=100233;
struct node {
    int v,id;
    bool operator < (node a) const {
        return v>a.v;
    }
}b[N];
int tr[N];
int n,n1,n2,ans,cut;
int lowbit(int x){return x&-x;}
void add(int x) {
    for (;x<=n;x+=lowbit(x)) tr[x]++;
}
int query(int l,int r) {
    int sum=0;l--;
    for (;l;l-=lowbit(l)) sum-=tr[l];
    for (;r;r-=lowbit(r)) sum+=tr[r];
    return sum;
}
signed main() {
    freopen("sun.in","r",stdin);
    freopen("sun.out","w",stdout);  
    scanf("%lld%lld",&n1,&n2);n=n1+n2;cut=n1;
    for (int i=1,a;i<=n1;i++) scanf("%lld",&a),b[i].v=a,b[i].id=n1-i+1;
    for (int i=1,a;i<=n2;i++) scanf("%lld",&a),b[i+n1].v=a,b[i+n1].id=i+n1;
    sort(b+1,b+n+1);
    for (int i=1;i<=n;i++) {
        int v=b[i].id;
        if (v<=cut) {
            ans+=cut-v;ans-=query(v,cut);
            cut=v;
            add(v);
        }
        else {
            ans+=v-cut-1;
            ans-=query(cut+1,v);
            cut=v-1;
            add(v);
        }
    }
    printf("%lld\n",ans);
}

猜你喜欢

转载自blog.csdn.net/qq_41893580/article/details/80514328
t1
今日推荐