CF1654E Arithmetic Operations 题解
题目让我们求改变数字的最少次数,那我们转化一下,
求可以保留最多的数字个数 \(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 题解的更多相关文章
- Continuity of arithmetic operations
Arithmetic operations taught in elementary schools are continuous in the high level topological poin ...
- codechef Row and Column Operations 题解
版权声明:本文作者靖心,靖空间地址:http://blog.csdn.net/kenden23/,未经本作者同意不得转载. https://blog.csdn.net/kenden23/article ...
- 等差数列Arithmetic Progressions题解(USACO1.4)
Arithmetic Progressions USACO1.4 An arithmetic progression is a sequence of the form a, a+b, a+2b, . ...
- 多校第九场Arithmetic Sequence题解
题目链接:http://acm.hdu.edu.cn/showproblem.php? pid=5400 题意:给定等差数列的差值d1,d2.问长度为n的数列中有多少个满足条件的子序列,条件为子序列中 ...
- 【CF1443F】Identify the Operations 题解
原题链接 题意简介 建议去原题看.这题意我表达不清楚. 大概就是给你一个 n 的排列,现在要求你进行 m 次操作. 每次操作,你会在现有的排列中删去一个数,然后选择其左边或右边的一个与之相邻的数加入 ...
- [UCSD白板题] Maximize the Value of an Arithmetic Expression
Problem Introduction In the problem, your goal is to add parentheses to a given arithmetic expressio ...
- Project Euler 93:Arithmetic expressions 算术表达式
Arithmetic expressions By using each of the digits from the set, {1, 2, 3, 4}, exactly once, and mak ...
- 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 ...
- 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 ...
- Algebraic Foundations ( Arithmetic and Algebra) CGAL 4.13 -User Manual
理解: 本节主要介绍CGAL的代数结构和概念之间的互操作.与传统数论不同,CGAL的代数结构关注于实数轴的“可嵌入”特征.它没有将所有传统数的集合映射到自己的代数结构概念中,避免使用“数的类型”这一术 ...
随机推荐
- Linx 阶段一
Linux Linux常用命令 具体演示 1). ls 2). pwd 3). touch 4). mkdir 5). rm 使用技巧 1. 连按 Tab健自动补齐文件名 2. ll 查看当前目录文件 ...
- c语言趣味编程(4)抓交通肇事犯
一.问题描述 一辆卡车违反交通规则,撞人后逃跑.现场有三人目击该事件,但都没有记住车号,只记下车号的一些特征. 甲说:牌照的前两位数字是相同的: 乙说:牌照的后两位数字是相同的,但与前两位不同: 丙是 ...
- 这是一篇记录——django-xadmin重新开发记录
利用下面的代码把django的版本换成和xadmin2适配的版本,注意xadmin最新版本出了3.0但是就是一个纯前端的框架,和之前的版本差异较大. 因为此时距离ddl不到24小时,所以使用旧的版本. ...
- 以SQLserver为例的Dapper详细讲解
Dapper是一种轻量级的ORM(对象关系映射)工具,它提供了高效且易于使用的方式来执行数据库操作.Dapper是由Stack Overflow团队开发并维护的,它的主要目标是提供比EF更快.更直接的 ...
- Qt+MySql开发笔记:Qt5.9.3的msvc2017x64版本编译MySql8.0.16版本驱动并Demo连接数据库测试
前言 mysql驱动版本msvc2015x32版本调好, mysql的mingw32版本的驱动上一个版本编译并测试好,有些三方库最低支持vs2017,所以只能使用msvc2017x64,基于Qt5 ...
- NC20279 [SCOI2010]序列操作
题目链接 题目 题目描述 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成 ...
- 【解决方法】windows连接域时报错:An Active Directory Domain Controller(AD DC) for the domain“chinaskills.com“....
目录-快速跳转 问题描述 原因分析: 解决方案: 附言: 问题描述 操作环境与场景: 在 VM 内 windos 2019 在连接到域时,提示报错: An Active Directory Domai ...
- MySQL百万数据深度分页优化思路分析
业务场景 一般在项目开发中会有很多的统计数据需要进行上报分析,一般在分析过后会在后台展示出来给运营和产品进行分页查看,最常见的一种就是根据日期进行筛选.这种统计数据随着时间的推移数据量会慢慢的变大,达 ...
- Mysql列转行, group_concat的使用
开始业务的查询的时候碰到一个sql的查询语句问题,主要是 group_concat 之前没用过,现在记录一下怎么用 group_concat 用法, 可以将相同的行组合起来 group_concat( ...
- 2022-02-16:将数组分割成和相等的子数组。 给定一个有 n 个整数的数组,你需要找到满足以下条件的三元组 (i, j, k) : 0 < i, i + 1 < j, j + 1 < k < n
2022-02-16:将数组分割成和相等的子数组. 给定一个有 n 个整数的数组,你需要找到满足以下条件的三元组 (i, j, k) : 0 < i, i + 1 < j, j + 1 & ...