摘自我的洛谷博客。

题目让我们求改变数字的最少次数,那我们转化一下,

求可以保留最多的数字个数 \(cnt\),再用 \(n\) 减一下就行,即 \(res = n - cnt\)。

我们先考虑两种暴力方法。

第一种暴力方法:

大体思路:因为要保留的最多,那么我们肯定要在众多等差数列中找能对应数字最多的那一个并保留下来。

首先,我们要知道一个概念。

对于这道题,那么我们可以暴力枚举公差 \(d\)(就是数组中相邻两项的差值都是 \(d\),并把题目中的每个 \(a[i]\) 对应的等差数列的最后一项 \(a[i] + d \times (n - i)\) 计算出来。


对于同一个公差 \(d\),如果不同位置计算出来的序列的最后一个值相同,那就说明它们属于同一个等差数列。

如果有 \(x\) 个数字计算出来的最后一个值都相同,那么采用其对应的等差数列作为修改后的数组,这 \(x\) 个数字是不需要改变的,只需要改变 \(n - x\) 个数字。

那我们可以想到,用桶记录计算出来的值 \(x\) 的出现次数 \(a[x]\)。如果某一次计算出来的值为 \(x\),那么可以将 \(a[x]\) 加 \(1\)。

如果 \(a[x]\) 是 \(a\) 中最大的元素,那么说明,以 \(a[x]\) 为结尾的等差数列中存在的元素数量最多,那么更改数字的数量也就减少了,只需要 \(n - a[x]\) 个元素。

这种方法的时间复杂度为 \(O(DN)\),\(D\) 为需要枚举的公差数量。

第二种暴力方法:

考虑动态规划,设 \(f[i][j]\) 表示以 \(a[i]\) 为等差数列最后一个元素的以 \(j\) 为公差的等差数列最多可以保留的数字个数

我们可以枚举上一个数字 \(a[k]\),如果它与 \(a[i]\) 在同一等差数列,那么有 \(f[i][j] = f[k][j] + 1\),表示又可以多保存一个数字了。

那这个序列的公差是多少呢?

这样考虑,中间有 \(i - k\) 个公差,差了 \(a[i] - a[k]\),那么公差就是\(\frac{a[i] - a[k]}{i - k}\)。

如果除不尽怎么办呢,那么这就说明 \(a[i]\) 和 \(a[k]\) 不能在同一个等差数列,不然公差为小数!

那 \(k\) 从哪里开始枚举呢?从 \(1\) 开始是不是太慢了?

这个等会儿讲。


那么为了平衡这两种暴力算法,我们可以这样办:

取输入的数列 \(a\) 的最大值 \(m\)。

我们只使用第一种方法枚举 \([0, \sqrt m]\) 的部分,时间复杂度为 \(O(n \sqrt m)\)。

我们使用第二种方法枚举 \([\sqrt m + 1, n]\) 的部分。

下面探讨第二种方法的时间复杂度,

首先回归到前面的问题,来探讨 \(k\)(\(i\) 的上一位数字在哪里) 从何处开始枚举,到哪里。

到哪里好解决,就是 \(i - 1\)。

而开始的地方,是 \(i - \sqrt m\)。为啥呢?

首先,因为公差 \(D\) 在 \([\sqrt m + 1, n]\) 之间,所以 \(D > \sqrt m\),那么我们计算差值 \(a[i] - a[k] = (a[k] + (i - k) \times D) - a[k] = (i - k) \times D > (i - k) \times \sqrt m\)。

首先假设 \(i, k\) 都在同一个等差数列中,如果 \(k+ \sqrt m < i\),那么\(a[i] - a[k] > (i - k) \times \sqrt m > \sqrt m \times \sqrt m = m\),这样的话,两数之差竟然比 \(m\) 还要大,不成立,

所以 \(k + \sqrt m \geq i\),也就是说 \(k\) 要从 \(i - \sqrt m\) 开始枚举。

所以,第二种方法的时间复杂度为 \(O(n \sqrt m)\)。

那么这个题的时间复杂度就为 \(O(n \sqrt m)\)。

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <unordered_map> using namespace std; const int N = 100010; int n;
int a[N], maxx, sqrtmaxx; int u[(int)(N + N * sqrt(N))]; // 第一种暴力方法的桶
unordered_map<int, int> f[N]; // 第二种暴力方法的动态规划数组。 int max_keep() {
int ans = 0;
for (int d = 0; d <= sqrtmaxx; d++) { // 第一种暴力方法,枚举公差 D
for (int i = 1; i <= n; i++) {
ans = max(ans, ++u[a[i] + (n - i) * d]);
}
for (int i = 1; i <= n; i++) {
u[a[i] + (n - i) * d]--;
}
} for (int i = 1; i <= n; i++) { // 第二种暴力方法,动态规划
for (int j = max(1, i - sqrtmaxx); j < i; j++) {// j只用从 i - sqrt(m) 开始枚举
if ((a[i] - a[j]) % (i - j) == 0) {
int x = (a[i] - a[j]) / (i - j);
if (x <= sqrtmaxx) continue;
f[i][x] = max(f[i][x], f[j][x] + 1);
ans = max(f[i][x] + 1, ans);
}
}
} for (int i = 1; i <= n; i++) f[i].clear(); // 清空数组 return ans;
} int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i], maxx = max(maxx, a[i]);
sqrtmaxx = sqrt(maxx); int ans1 = 0, ans2 = 0;
ans1 = max_keep();
reverse(a + 1, a + n + 1); // 应对公差为负数的情况
ans2 = max_keep(); cout << n - max(ans1, ans2) << '\n';
return 0;
}

CF1654E Arithmetic Operations 题解的更多相关文章

  1. Continuity of arithmetic operations

    Arithmetic operations taught in elementary schools are continuous in the high level topological poin ...

  2. codechef Row and Column Operations 题解

    版权声明:本文作者靖心,靖空间地址:http://blog.csdn.net/kenden23/,未经本作者同意不得转载. https://blog.csdn.net/kenden23/article ...

  3. 等差数列Arithmetic Progressions题解(USACO1.4)

    Arithmetic Progressions USACO1.4 An arithmetic progression is a sequence of the form a, a+b, a+2b, . ...

  4. 多校第九场Arithmetic Sequence题解

    题目链接:http://acm.hdu.edu.cn/showproblem.php? pid=5400 题意:给定等差数列的差值d1,d2.问长度为n的数列中有多少个满足条件的子序列,条件为子序列中 ...

  5. 【CF1443F】Identify the Operations 题解

    原题链接 题意简介 建议去原题看.这题意我表达不清楚. 大概就是给你一个 n 的排列,现在要求你进行 m 次操作. 每次操作,你会在现有的排列中删去一个数,然后选择其左边或右边的一个与之相邻的数加入 ...

  6. [UCSD白板题] Maximize the Value of an Arithmetic Expression

    Problem Introduction In the problem, your goal is to add parentheses to a given arithmetic expressio ...

  7. Project Euler 93:Arithmetic expressions 算术表达式

    Arithmetic expressions By using each of the digits from the set, {1, 2, 3, 4}, exactly once, and mak ...

  8. Algebraic Kernel ( Arithmetic and Algebra) CGAL 4.13 -User Manual

    1 Introduction Real solving of polynomials is a fundamental problem with a wide application range. T ...

  9. Modular Arithmetic ( Arithmetic and Algebra) CGAL 4.13 -User Manual

    1 Introduction Modular arithmetic is a fundamental tool in modern algebra systems. In conjunction wi ...

  10. Algebraic Foundations ( Arithmetic and Algebra) CGAL 4.13 -User Manual

    理解: 本节主要介绍CGAL的代数结构和概念之间的互操作.与传统数论不同,CGAL的代数结构关注于实数轴的“可嵌入”特征.它没有将所有传统数的集合映射到自己的代数结构概念中,避免使用“数的类型”这一术 ...

随机推荐

  1. FormData收集表单信息&并且转化为Json格式进行提交验证

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  2. React课堂笔记2

    一.JSX 1.1.什么是JSX JSX = JavaScript XML,这是React官方发明的一种JS语法(糖) 概念:JSX是 JavaScript XML(HTML)的缩写,表示在 JS 代 ...

  3. C++核心知识回顾(自定义数据类型)

    复习C++ 类 自定义数据类型最灵活的方式就是使用C++的类结构 现在定义一个货币类型Currency: enum signType{PLUS,MINUS}; class Currency { pub ...

  4. DeFi-W3

    Gas Fee 每一笔交易都会产生Gas Fee. GWei ETH的最小单位 出价(gas fee)的高低会影响交易上联的速度,越快就价格越高. gas fee是跟具体的计算量有关的 Smart c ...

  5. uniapp directive 在原生 wgt 包不生效 uniapp directive 不生效

    需求 根据权限编码禁用按钮 阻止当前 dom 绑定的点击事件,禁用状态(opacity 半透明?? 或者 display: none?? ) 尝试 开发环境用 Chrome 跑,一切正常,构建打包后去 ...

  6. Ansible 常用基础模块

    Ansible 常用基础模块 目录 Ansible 常用基础模块 Ansible的执行 Ansible ad-hoc ad-hoc模式的使用场景 ad-hoc模式的命令使用 ad-hoc结果返回颜色 ...

  7. 爆肝一周,我开源了ChatGPT 中文版接口,官方1:1镜像支持全部 官方接口

    这里实现我之前文章承诺承接上文 人人实现ChatGPT自由,手把手教你零撸部署自己聊天私服 现在ChatGPT 提供了api接口 可以让我自己对接去实现我们自己想要gpt应用,但是由于一些原因,国内也 ...

  8. Django4全栈进阶之路9 STATIC静态文件路径设置、MEDIA媒体文件路径设置

    在 Django 4 中,可以在 settings.py 文件中设置 STATICFILES_DIRS 来指定应用程序静态文件所在的文件夹路径,设置 STATIC_ROOT 来指定收集所有应用程序静态 ...

  9. OData WebAPI实践-与ABP vNext集成

    本文属于 OData 系列文章 ABP 是一个流行的 ASP. NET 开发框架,旧版的的 ABP 已经能够非常好的支持了 OData ,并提供了对应的 OData 包. ABP vNext 是一个重 ...

  10. 一分钟学一个 Linux 命令 - cat 和 tail

    前言 大家好,我是 god23bin.今天我给大家带来的是 Linux 命令系列,每天只需一分钟,记住一个 Linux 命令不成问题.今天,需要你花费两分钟时间,因为我们要介绍的是两个常用的查看文件内 ...