摘自我的洛谷博客。

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

求可以保留最多的数字个数 \(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. Go For Web:踏入Web大门的第一步——Web 的工作方式

    前言: 本文作为解决如何通过 Golang 来编写 Web 应用这个问题的前瞻,对 Golang 中的 Web 基础部分进行一个简单的介绍.目前 Go 拥有成熟的 Http 处理包,所以我们去编写一个 ...

  2. ip addr命令解析

    转载请注明出处: 1.ip addr命令使用解析 ip addr 命令是Linux系统中的一个网络管理工具,用于显示和配置系统中的网络接口及其地址信息.它可以列出系统中所有的网络接口及其详细信息,包括 ...

  3. 关于Java中值传递和址传递

    参数传递在Java中有两种类型 值和址 其实本质都是一份拷贝 在调用函数的时候 进行压栈 传进来的参数会被开辟一份新的空间 传基本类型是把值传过去 传引用数据类型是实例指向实参 void m(int ...

  4. Appweb交叉编译

    Appweb交叉编译 编译环境:ubuntu-12.04 x64 开发平台:Hi3535 arm版 编译版本:appweb-6.1.1.zip 下载地址=> Appweb web site: h ...

  5. Swift下Data处理全流程:从网络下载,数模转换,本地缓存到页面使用

    Swift下将网络返回json数据转换成struct 假如网络请求返回的数据结构是一个深层嵌套的Json 首先要通过key-value取出这个json中的数据源 // 将返回的json字符串转Dict ...

  6. docker安装es,单机集群模式.失败。

    操作系统:mac系统. docker run -d --name es1 -p 9201:9200 -p 9301:9300 elasticsearch:7.14.0 docker run -d -- ...

  7. Django4全栈进阶之路17 项目实战(用户管理):user_add.html用户新增画面设计

    1.模块: {% extends 'base.html' %} {% block content %} <div class="card mt-3"> <div ...

  8. upload-labs 第一关 前端验证绕过!

    打开靶场发现只能上传jpg png gif 的文件格式的文件,我们想要上传上去的文件格式为php文件格式,首先在Notepad++里面打开图片,会出现很多乱码,我们在最后面添加漏洞语句<?php ...

  9. css设置边框四角样式

    开发中使用css 伪类 是再常见不过的事情了,运用好了能轻松实现许多复杂的样式,大大减少使用图片消耗带宽的问题,今天我们就使用伪类来实现登录框的四角样式 html代码如下 <div class= ...

  10. 【python基础】if语句-条件测试

    1.初识if语句 编程时经常需要检查一系列条件,并据此决定采取什么措施.在Python中,使用if语句能够检查程序的当前状态,并据此采取相应措施. 其语法格式之一: 假设有一个学员名单的列表,想将其中 ...