2016级算法第二次上机-F.ModricWang's Number Theory II
891 ModricWang's Number Theory II
思路
使得序列的最大公约数不为1,就是大于等于2,就是找到一个大于等于2的数,它能够整除序列中的所有数。
考虑使得一个数d整除数组中所有数的代价:
如果一个数不能被b整除,那么可以花费x的代价删掉它,或者通过多次加1使得它可以被d整除,代价应该为 \((d - a[i]\%d) * y\) , \((a[i] \% d == 0s时特判,应该为0)\)
令 \(l = x / y\)
如果\(d - a[i] \% d <= l\) \((a[i]\%d != 0)\), 这个数产生的代价是 \((d - a[i] \% d) * y\) , 否则是\(x\)。
所有代价求和就是总代价,最小的总代价就是答案。
但是这样枚举了d和a[i], 复杂度是\(O(n^2)\) 的。
考虑将a[i]换一种方式存储:b[i]表示值为i的数出现的次数。
这样d可以将b分成如下若干段:
\([0, d - 1], [d, d * 2 - 1], [d * 2, d * 3 - 1], ... ,[d * i, d * (i + 1) - 1]\)
对于每一段而言,
\([d * (i + 1) - l, d * (i + 1) - 1]\) 内的数应该通过多次加1变成\(d * (i + 1)\) ,
代价应为 \((该区间内数的个数 * d * (i + 1) - 该区间内的数之和) * y\)
\([d * i + 1 , d * (i + 1) - l - 1]\) 内的数应该直接删除,
代价应为 \(该区间内的个数 * x\)
通过构造相应的前缀和数组,上述操作均可以在\(O(1)\) 的时间复杂度内完成
具体操作时应该注意边界
因为合数会被质数整除,因此d可以只枚举质数。
计算时间复杂度需要一些数论知识。首先素数密度(也就是 \(\frac{小于n的素数}{n}\) )可以参见oeis A006880,一个近似解析式为 \(\frac{1}{ln(n)}\),那么\(小于n的素数的总个数\)可以近似为 \(\frac{n}{ln(n)}\)
设小于等于n的素数为\(prime[i]\),素数总数为\(P\),取近似\(P=\frac{n}{ln(n)}\)
求结果部分的复杂度可以写为 \(\sum_{1}^{P} \frac{n}{prime[i]}\)
参见wikipedia,素数的倒数和又可以近似为 \(\sum_{1}^{p} \frac{1}{prime[i]}=ln(ln(n))\)
因此 \(\sum_{1}^{P} \frac{n}{prime[i]} = O(n* ln(ln(n)))\)
这里得到了计算结果部分的复杂度,还需要加上求素数这个过程的时间复杂度。如果使用朴素筛法,求复杂度的过程正好的上文所述的完全一致,其复杂度为\(O(n*ln(ln(n)))\)。如果使用欧拉筛求素数,复杂度为\(O(n)\)。
因此\(O(运行时间)=O(求素数)+O(计算结果)=O(n*ln(ln(n)))\)
代码
#include<iostream>
#include<cstring>
using namespace std;
const long long Max_Ai = 1000000*2;
long long n, x, y, l;
long long nums[Max_Ai + 10];
long long s[Max_Ai + 10], sum[Max_Ai + 10];
bool valid[Max_Ai + 10];
long long prime[Max_Ai + 10];
long long tot;
//线性筛求素数
void init_prime() {
memset(valid, true, sizeof(valid));
for (int i = 2; i <= Max_Ai; i++) {
if (valid[i]) prime[++tot] = i;
for (int j = 1; j <= tot && i*prime[j] <= Max_Ai; j++) {
valid[i*prime[j]] = false;
if (i%prime[j]==0) break;
}
}
}
int main() {
#ifdef ONLINE_JUDGE
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#endif
init_prime();
cin >> n >> x >> y;
l = x/y;
for (long long i = 1; i <= n; i++) {
long long p;
cin >> p;
nums[p]++; //这是一种比较特别的数字记录方法,原理类似于基数排序radix sort
}
for (long long i = 1; i <= Max_Ai; i++) {
s[i] = s[i - 1] + nums[i]; //数量和
sum[i] = sum[i - 1] + nums[i]*i; //前缀和
}
auto min_cost = (long long) 1e18;
for (long long i = 1; i <= tot; i++) {
long long k = prime[i];
long long now_cost = 0;
for (long long j = 0; j <= Max_Ai; j += k) {
long long mid = max(j + k - l - 1, j);
long long bound = min(j + k - 1, Max_Ai);
if (bound > mid) {
now_cost += ((s[bound] - s[mid])*(j + k) - (sum[bound] - sum[mid]))*y;
now_cost += (s[mid] - s[j])*x;
} else {
now_cost += (s[bound] - s[j])*x;
}
}
min_cost = min(min_cost, now_cost);
}
cout << min_cost << "\n";
return 0;
}
2016级算法第二次上机-F.ModricWang's Number Theory II的更多相关文章
- 2016级算法第二次上机-G.ModricWang's Real QuickSort
873 思路 这是一道非常基础的题,目的是帮助大家回顾快排相关的知识.大家完成此题之后应该就对快排有比较深刻的印象了. 对于整个快排的流程,题目描述中已经给了清晰完整的伪代码.需要自己加工的部分就是, ...
- 2016级算法第二次上机-E.AlvinZH的儿时梦想——运动员篇
862-AlvinZH的儿时梦想--运动员篇 思路 难题. 应该想到,不管给出的数据如何,每一个淘汰的人不会对最终答案产生任何影响,所以每次淘汰就把人除掉就可以了,最后剩下的两个人计算它们从开始到相遇 ...
- 2016级算法第二次上机-D.Bamboo的饼干
Bamboo的饼干 分析 从两个数组中各取一个数,使两者相加等于给定值.要注意去重和排序 难度不大,方法很多,基本只要不大于O(n^2 ) 的都可以过.本意想考察二分搜索 还可以借助stl中的map, ...
- 2016级算法第二次上机-C.AlvinZH的儿时梦想——坦克篇
872 AlvinZH的儿时梦想----坦克篇 思路 简单题.仔细看题,题目意在找到直线穿过的矩形数最小,不能从两边穿过.那么我们只要知道每一行矩形之间的空隙位置就可以了. 如果这里用二维数组记住每一 ...
- 2016级算法第二次上机-B.Bamboo的OS实验
Bamboo的OS实验 分析 首先理解题意,要完成不同数量的不同命令,但是完成相同的命令之间必须有n个间隔,为使得时间最短,自然优先用其他命令来填充这n分钟的时间,由于数量少的命令可以用来填充空隙,所 ...
- 2016级算法第二次上机-A.画个圈圈诅咒你
890 画个圈圈诅咒你 思路 简单题.题目中的圆并没有什么实际作用,简化成线段重合问题会更好理解些. 暴力解法:使用双重for循环会T到想哭,记住最直接的方法一般是过不了题的. 解法一:二分查找.空间 ...
- 2016级算法期末模拟练习赛-F.AlvinZH的青春记忆IV
1086 AlvinZH的青春记忆IV 思路 难题,动态规划. 这是一道很有意思的题,因为它不仅卡了时间,也卡了空间,而且卡的很妙很迷. 光是理解题意已经有点难度,简化题意:两串数字序列,相等的数字定 ...
- 题解:2018级算法第二次上机 Zexal的流水线问题
题目描述: 样例: 实现解释: 最基础的流水线调度问题,甚至没有开始和结束的值 实现方法即得出状态转移方程后完善即可,设a[][i]存储着第一二条线上各家的时间花费,t[][i]存储着i处进行线路切换 ...
- 题解:2018级算法第二次上机 Zexal的排座位
题目描述: 样例: 实现解释: 一道看似复杂但实际既是斐波那契变形的题目 知识点:递推,斐波那契 通过问题的描述,可以得到以下规律:(除了座位数为一时)男生坐最后时,倒数第二个一定是女生:女生坐最后, ...
随机推荐
- require.js的用法(转)
一.为什么要用require.js? 最早的时候,所有Javascript代码都写在一个文件里面,只要加载这一个文件就够了.后来,代码越来越多,一个文件不够了,必须分成多个文件,依次加载.下面的网页代 ...
- shiro 集成spring 使用 redis作为缓存 学习记录(六)
1.在applicationContext-redis.xml配置文件中增加如下: 申明一个cacheManager对象 用来注入到 shiro的 securityManager 属性 cac ...
- Cisco VPP启动流程
Cisco VPP启动流程,有需要的朋友可以参考一下. VPP初始化 VLIB_INIT_FUNCTION用来定义构造函数,注册函数到vlib_main_t->init_function_reg ...
- C#HTML解析利器HtmlAgilityPack
HtmlAgilityPack是一个开源的解析HTML元素的类库,最大的特点是可以通过XPath来解析HMTL,如果您以前用C#操作过XML,那么使用起HtmlAgilityPack也会得心应手.目前 ...
- JMS 之 Active MQ 的消息传输
本文使用Active MQ5.6 一.消息协商器(Message Broker) broke:消息的交换器,就是对消息进行管理的容器.ActiveMQ 可以创建多个 Broker,客户端与Active ...
- mysql 用户创建,修改和忘记root密码的操作
#创建用户CREATE USER 'zzq'@'localhost' IDENTIFIED by 'zzq';#flush privileges 命令本质上的作用是将当前user和privilige表 ...
- Web图片编辑控件发布-Xproer.ImageEditor
版权所有 2009-2014 荆门泽优软件有限公司 保留所有权利 官方网站:http://www.ncmem.com 产品首页:http://www.ncmem.com/webplug/image-e ...
- 使用#include消除重复代码
消除重复代码代码很多种,比如: 1)提炼成函数复用 2)使用宏 3)继承 4)使用闭包(boost::bind.boost::function) 上述是最为常用的,对于C++程序,闭包可能用得相对少一 ...
- Linux基础系统权限
Linux基础系统权限 文件权限 Linux中,每个文件拥有三种权限 权限 对文件的影响 对目录的影响 r(读取) 可读取文件 可列出目录内容 w(写入) 可修改文件内容 可在目录中创建删除文件 x( ...
- unittest对单个测试类的多种测试执行方法总结
基于unittest测试框架编写的测试脚本,一般单个测试类下会有多个测试方法,unittest也提供多种测试执行方式,下面就不同方式或者需求一一实操并说明: 一.使用unittest下main()方法 ...