蓝桥杯 —— 小朋友排队 —— 树状数组

来源:互联网 发布:将军乃有宇宙之号乎 编辑:程序博客网 时间:2024/05/17 00:09


问题描述
  n 个小朋友站成一排。现在要把他们按身高从低到高的顺序排列,但是每次只能交换位置相邻的两个小朋友。

  每个小朋友都有一个不高兴的程度。开始的时候,所有小朋友的不高兴程度都是0。

  如果某个小朋友第一次被要求交换,则他的不高兴程度增加1,如果第二次要求他交换,则他的不高兴程度增加2(即不高兴程度为3),依次类推。当要求某个小朋友第k次交换时,他的不高兴程度增加k。

  请问,要让所有小朋友按从低到高排队,他们的不高兴程度之和最小是多少。

  如果有两个小朋友身高一样,则他们谁站在谁前面是没有关系的。
输入格式
  输入的第一行包含一个整数n,表示小朋友的个数。
  第二行包含 n 个整数 H1 H2 … Hn,分别表示每个小朋友的身高。
输出格式
  输出一行,包含一个整数,表示小朋友的不高兴程度和的最小值。
样例输入
3
3 2 1
样例输出
9
样例说明
  首先交换身高为3和2的小朋友,再交换身高为3和1的小朋友,再交换身高为2和1的小朋友,每个小朋友的不高兴程度都是3,总和为9。
数据规模和约定
  对于10%的数据, 1<=n<=10;
  对于30%的数据, 1<=n<=1000;
  对于50%的数据, 1<=n<=10000;
  对于100%的数据,1<=n<=100000,0<=Hi<=1000000。

第一眼看到这个题想直接暴力,用一个复制的数组进行排序,然后用lower_bounder()-...找到每一个身高应该处在的位置。

再用一个MAP映射记录每个身高的学生的不满意程度,然后用两个for循环暴力求解。

但是越写越感觉有些做不到的地方,如果是有两个身高相同的学生的话,我该怎么记录两个不同学生的不满意程度呢,如果是有更多相同的呢。

然后我就放弃了这种直接暴力的方法。

这道题其实用到的是树状数组的算法,把所有的身高学生放入树状数组中,先正序放入一遍,得出每个学生前面有多少个高于他自己的学生个数;

然后再逆序放入一遍,得出每个学生后面有多少个身高小于他的学生个数。其实就是先表示每个学生在前面队列和后面队列的逆序数,

得到这个和之后,即得到该学生以该移动的次数,然后把所有的学生不满意程度加起来就很简单了。

但是这个题的评测系统有一个坑爹的地方,如果说我把记录最终结果的变量ans放在main()外面,就直接报错,第一个测试样例都过不了,

也是醉了,交了是好几遍。。。。


#include <iostream>#include <cstdio>#include <cstdlib>#include <string>#include <cmath>#include <algorithm>#include <cstring>#include <map>#include <sstream>#include <queue>#include <stack>#define INF 0x3f3f3f3f#define mem(a,b) memset(a,b,sizeof(a))#define For(a,b) for(int i = a;i<b;i++)#define ll long long#define MAX_N 100010using namespace std;const int maxn = 1000005;int x[maxn],m[maxn];ll b[MAX_N],cur[MAX_N];int lowbit(int p){    return p&(-p);}void add(int s,int t){    for(int i = s; i<maxn; i+=lowbit(i))        m[i] += t;}int sum(int s){    int an = 0;    for(int i = s; i>0; i-=lowbit(i))        an += m[i];    return an;}int main(){//    int i = lower_bound(a,a+6,4)-a;//    cout<<i<<endl;    int n;    cin>>n;    ll ans = 0;    cur[0] = 0;    mem(m,0);    for(int i = 1; i<=MAX_N; i++)        cur[i] = cur[i-1] + i;    for(int i = 0; i<n; i++)    {        cin>>x[i];        add(x[i]+1,1);        b[i] = (i+1) - sum(x[i]+1);    }    mem(m,0);    for(int i = n-1; i>=0; --i)    {        add(x[i]+1,1);        b[i] += sum(x[i]);    }    for(int i = 0; i<n; i++)    {        ans += cur[b[i]];    }    cout<<ans<<endl;    return 0;}





0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 手机主菜单坏了怎么办 索尼手机密码忘了怎么办 索尼笔记本密码忘了怎么办 索尼手机解锁密码忘了怎么办 索尼记录仪密码忘了怎么办 索尼z3手机忘记开机密码怎么办 索尼忘记锁屏密码怎么办 索尼手机忘记锁屏密码怎么办 忘了手机解锁图案怎么办 索尼手机忘记开机密码怎么办 索尼笔记本开机密码忘了怎么办 手机的开机密码忘了怎么办 联想手机开机密码忘了怎么办 红米note3忘记开机密码怎么办 小米2忘了密码怎么办 小米笔记本电脑忘记开机密码怎么办 小米笔记本忘记开机密码怎么办 小米手机儿童模式忘记密码怎么办 小米应用锁密码忘了怎么办 小米air密码忘了怎么办 小米4密码忘了怎么办 小米手机开机密码忘了怎么办? 小米笔记本电脑开机密码忘了怎么办 小米笔记本开机密码忘了怎么办 htc手机忘记解锁图案怎么办 红米手机屏幕锁定怎么解锁怎么办 小米5s有id怎么办 手机密码找不回来了怎么办? 手机密码图案忘了怎么办 手机屏幕图案锁忘了怎么办 捡到苹果7有id锁怎么办 魅族什么都忘了怎么办 海信电视百事通登陆失败怎么办 去哪儿换号了怎么办 ipan充不进去电怎么办 安卓数据线松了怎么办 索尼z5耳机掉漆怎么办 索尼z5无限重启怎么办 苹果8基带坏了怎么办 oppo手机忘记图案密码怎么办 电池充不进去电怎么办