题目

给 n 个实数 a_1, a_2 ... a_n, 要求计算这 n 个数两两之间差的绝对值下取整后的和是多少。

输入描述

第一行为一个正整数 n 和一个整数 m。接下来 n 行,第 i 行代表一个整数 b_i。a_i = b_i / m, i = 1...n。
n <= 1000: 5分
n <= 100000且 a_i 均为整数: 15分
n <= 100000 1 <= m <= 10^9 0 <= b_i <= 10^18: 25分

输出描述

一个整数

示例1
  • 输入

3 10
11
22
30

  • 输出

2

备注:

请选手在解题时注意精度问题
a_i 取值为 1.1,2.2 和 3.0
|1.1-2.2| 下取整为 1
|1.1-3.0| 下取整为 1
|2.2-3.0| 下取整为 0

思路

  • 1 . 暴力破解法。 直接遍历所有的情况,对两个数相减向下取整然后求和,时间复杂度为 O(n^2)。但要注意,浮点数在内存中的特殊表示方式,比如 1.66666666666666667 - 2.66666666666666667 向下取整后可能为 0,会造成计算错误。

  • 2 . 如果所有的数为整数,先对所有的数据按照升序排列。以 1 2 3 4 5 举例说明,|1-3| = |1-2+2-3| = |1-2| + |2-3|,|1-5| = |1-2+2-3+3-4+4-5| = |1-2| + |2-3| + |3-4| + |4-5|。可以看到,任意两个数的差都可以通过相邻两个数的差转换而来,因此,我们只需要统计相邻两个数的差总共被利用了多少次即可 。|1-2| 的差被 (1,2),(1,3),(1,4)(1,5) 共利用了 4 次{=1×4},|2-3| 的差被 (1,3),(1,4)(1,5),(1,3),(1,4)(1,5) 共利用了 6 次{=2×3},即某个区间的差值被利用的次数等于此区间左边数的个数乘以此区间右边数的个数,总的和就等于每段区间的差乘以利用的次数再求和。

  • 3 . 如果不是整数,有小数部分的话,我们再来看看会怎样。如果小数部分也是升序,比如 |1.1 - 2.2| 和 |1 - 2| 、|3.0 - 10.9| 和 |3 - 10| 取整后都是一样的。但如果小数部分,有降序的,比如 |1.2 - 2.1| 和 |1 - 2| 、|3.9 - 10.0| 和 |3 - 10|,前者就比后者取整后少了 1。因此,小数部分每有一个逆序的,也就是前面比后面大的,总的和就减去 1 即可。

  • 4 . 综上所述,我们可以将数字拆分为整数部分和小数部分,依据整数部分对数据升序排列,同时小数部分与整数部分作一致的调整。然后对整数部分相邻区间求差值并乘以对应的系数先求出总和,再求出小数部分的逆序对个数,总和减去逆序对数即为最终所求。其中,排序和求逆序对数的时间复杂度都可以做到 O(nlogn),因此算法总体复杂度也为 O(nlogn)。

代码实现{排序通过快排,求逆序对数采用归并排序}

// int 4 字节,long 8 字节
#include <iostream>
#include <cmath>
#include <stdio.h> using namespace std; void Quick_Sort(long data[], double frac[], int left, int right);
void Merge_Array(double data[], int left, int mid, int right, double temp[]);
void Merge_Sort(double data[], int left, int right, double sorted_data[]); int cnt = ; // 逆序对数 int main()
{
int n = , m = ;
cin >> n >> m; long b[n] = {};
long inte[n] = {}; // a_i 的整数部分
double frac[n] = {}; // a_i 的小数部分
int i = ; double data[n] = {};
for (i = ; i < n; i++)
{
cin >> b[i];
data[i] = double(b[i]) / m;
} // 暴力求解
long sum1 = ;
int j = ;
for (i = ; i < n-; i++)
{
for (j = i+; j < n; j++)
{
sum1 += floor(fabs(data[i] - data[j]));
}
}
cout << sum1 << endl; // 分别求出整数部分和小数部分
for (i = ; i < n; i++)
{
inte[i] = b[i] / m;
frac[i] = double(b[i]) / m - inte[i];
} // 整数部分升序排列,小数部分随整数部分同步调整
Quick_Sort(inte, frac, , n-); // 相邻区间差乘以系数求总和
int error[n-] = {};
long sum = ;
for (i = ; i < n-; i++)
{
error[i] = abs(inte[i] - inte[i+]);
sum += (i+) * (n-i-) * error[i];
} // 归并排序的同时求得小数部分逆序对数
double sorted_data[n] = {};
Merge_Sort(frac, , n-, sorted_data); sum -= cnt;
cout << sum << endl;
return ;
} void Quick_Sort(long data[], double frac[], int left, int right)
{
if (left < right)
{
int i = left, j = right;
long choice = data[i];
double temp = frac[i];
while(i < j)
{
while(i < j && data[j] >= choice)
{
j--;
}
if(i < j)
{// 小数部分随整数部分同步调整
data[i] = data[j];
frac[i] = frac[j];
i++;
}
while(i < j && data[i] <= choice)
{
i++;
}
if(i < j)
{// 小数部分随整数部分同步调整
data[j] = data[i];
frac[j] = frac[i];
j--;
}
}
data[i] = choice;//i=j 小数部分随整数部分同步调整
frac[i] = temp;//i=j
Quick_Sort(data, frac, left, i-);
Quick_Sort(data, frac, i+, right);
}
} // O(n(logn))
void Merge_Sort(double data[], int left, int right, double sorted_data[])
{
if(left < right)
{
int mid = (left + right) / ;
Merge_Sort(data, left, mid, sorted_data);
Merge_Sort(data, mid+, right, sorted_data);
Merge_Array(data, left, mid, right, sorted_data);
}
} void Merge_Array(double data[], int left, int mid, int right, double temp[])
{
int i = left, j = mid + ;
int k = ; while(i <= mid && j <= right)
{
if (data[i] < data[j] || fabs(data[i] - data[j]) <= 1e-)
{
temp[k++] = data[i++];
}
else // 左边序列某个数大于右边某个数,则左边序列此数后面的数均大于右边的数
{
temp[k++] = data[j++];
cnt += mid - i + ;
}
} while(i <= mid)
{
temp[k++] = data[i++];
}
while(j <= right)
{
temp[k++] = data[j++];
} for(i = ; i < k; i++)
{
data[left+i] = temp[i];
}
}

个人见解,如有错误,欢迎指正与交流!

获取更多精彩,请关注「seniusen」!

 

今日头条 2018 AI Camp 6 月 2 日在线笔试编程题第二道——两数差的和的更多相关文章

  1. 今日头条 2018 AI Camp 5 月 26 日在线笔试编程题第二道——最小分割分数

    题目: 给 n 个正整数 a_1,…,a_n, 将 n 个数顺序排成一列后分割成 m 段,每一段的分数被记为这段内所有数的和,该次分割的分数被记为 m 段分数的最大值.问所有分割方案中分割分数的最小值 ...

  2. 今日头条 2018 AI Camp 5 月 26 日在线笔试编程题第一道——最佳路径

    题目 给定一个 n*m 的矩阵 A ,矩阵中每一个元素为一个十六进制数.寻找一条从左上角都右下角的路径,每次只能向右或者向下移动, 使得路径上所有数字之积在 16 进制下的后缀 0 最少. 输入描述: ...

  3. 今日头条 2018 AI Camp 6 月 2 日在线笔试编程题第一道——最大连续区间和扩展

    题目 给出一个长度为 n 的数组a1.a2.....ana1.a2.....an,请找出在所有连续区间 中,区间和最大同时这个区间 0 的个数小于等于 3 个,输出这个区间和. 输入描述: 第一行一个 ...

  4. 今日头条 2018 AI Camp 视频面试

    1. 本次面试是在牛客网平台进行的,没有涉及到技术细节,面试官也说仅仅是聊天.但是,不知道是网络卡顿还是平台缘故,连接非常不稳定,经常听不到声音,对方那边噪音也特别大,面试体验不是很好. 2. 面试时 ...

  5. 链家2018春招C/C++开发实习生在线考试编程题

    题目一 题解:该题目意思就是让你输入n组数据,然后求并集,利用STL容器set集合的特性:元素不重复存储,我们可以很轻易得出答案 #include <iostream> #include ...

  6. 今日头条 CEO 张一鸣:面试了 2000 个年轻人,混得好的都有这 5 种特质

    https://blog.csdn.net/qq_35246620/article/details/72801285 博主说:多了解了解总是好的. 正文 张一鸣算是 80 后中绝对的佼佼者.1983 ...

  7. 路冉的JavaScript学习笔记-2015年1月23日

    1.JavaScript的数据类型 A.原始类型:包含数值.字符串.布尔值.空值(null)和未定义值(undefined). Js原始类型均为不可改变类型.对不可变类型调用任何自带方法都不会改变原始 ...

  8. 8月1日起,这些新政将影响移动互联网产业-b

    今天,国家互联网信息办公室发布<移动互联网应用程序信息服务管理规定>.这项规定将从8月1日起生效,其中侧重对两类玩家提出了监管意见,他们分别是: 移动互联网应用程序提供者,即提供信息服务的 ...

  9. 优步UBER司机全国各地奖励政策汇总 (4月4日-4月10日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

随机推荐

  1. Java 加密PDF设置密码并添加水印

    /** * Project Name:XXX * File Name:EncryptLogFile.java * Date:2016-6-12上午11:56:38 * Copyright (c) 20 ...

  2. windows下搭建python

    windows下搭建python 下载python版本  https://www.python.org/   注意当前操作系统的位数,32位还是64位 同时   安装后  修改环境变量         ...

  3. 构建Linux根文件系统(未完待续)

          所谓制作根文件系统, 就是创建各种目录, 并且在里面创建各种文件. 比如在/bin ./sbin 目录下存放各种可执行程序, 在/etc 目录下存放配置文件, 在/lib 目录下存放库文件 ...

  4. 在CentOS7系统上安装MySQL数据库

    1.下载安装MySQL官方repo文件 下载MySQL的官方repo文件 [root@centos7 ~]# wget -i -c http://dev.mysql.com/get/mysql57-c ...

  5. 工具类(设置控件 frame) - iOS

    为了便于日常开发效率,因此创建了一些小的工具类便于使用. 具体 code 如下: 声明: #import <UIKit/UIKit.h> @interface UIView (Frame) ...

  6. php第二节(变量、常量)

    <?php /** * 类型转换 * 自动转换 数据在运算过程中自动转换 * 空字符串 false * "0" false * null false * 0 false * ...

  7. 新疆大学ACM-ICPC程序设计竞赛五月月赛(同步赛)-B-杨老师游戏

    题目链接:杨老师游戏 题目分析:将9个数字分成3块,分块枚举,话句话说,9个数字的所有排列组合,如果满足N=a*b-c就是一个答案,暴力枚举Orz. 代码如下:  #include<iostre ...

  8. 台式机上如何配置并使用苹果iPhone的耳机麦克风 并且麦克风开启降噪功能

    这个资料和技巧在网络上面很少有人分享,但是可能会有不少人需要这个东西.这里分享下经验.这也是一个困扰我很久的一个问题.因为买来了这个转接头,发现,录音的时候iPhone的耳机麦克风有很大的噪音无法消除 ...

  9. 关于Linux环境变量DISPLAY的设置

    问题描述:在个人PC(windows系统)安装了虚拟机,虚拟机中安装了Linux系统,Linux系统中安装了wireshark和firefox这两个程序,网上查阅可以通过设置DISPLAY环境变量指向 ...

  10. linux服务基础之ftp服务

    ftp是一种文件传输协议,我们以redhat6.9为服务器系统,来介绍一下ftp服务器,这里我们先介绍一下ftp协议工作的原理 ftp协议可以在不同类型的计算机之间传输文件,工作流程大致为 1:客户机 ...