等差数列
等差数列
给定一个长度为 的正整数数列 和一个正整数 。
你可以对数列进行以下两种操作:
+ i x ,增加操作,将 的值增加 ()。
- i x ,减少操作,将 的值减少 ()。
要求:在任何时候,你都需要保证每个 的值都是正整数。
请你使用尽可能少的操作次数,使得数列能够满足:对于所有 (), 均成立。
请你输出所需要的最少操作次数以及对应的具体操作方案。
输入格式
第一行包含两个整数 。
第二行包含 个整数 。
输出格式
第一行输出一个整数 ,表示所需要的最少操作次数。
接下来 行,用来输出具体操作方案,每行输出一个具体操作 + i x 或 - i x。你需要保证输出的 和 均为正整数,且 。
如果最少操作次数的方案不唯一,则输出任意一种方案均可。
数据范围
前 个测试点满足 。
所有测试点满足 ,,。
输入样例1:
4 1 1 2 1 5
输出样例1:
2 + 3 2 - 4 1
输入样例2:
4 1 1 2 3 4
输出样例2:
0
输入样例3:
7 1 1 1 2 3 4 5 6
输出样例3:
6 + 2 1 + 3 1 + 4 1 + 5 1 + 6 1 + 7 1
解题思路
先给出我的做法,当时做的时候没写出来,今天回来补题又写出来了。
首先我们不考虑改变,可以发现就是要把序列变成一个以为首项,公差为的等差数列,而现在固定,意味着其余项都是一个固定的值,因此如果原序列的,那么就要改变一次,因此最小改变次数就是与对应项不同的个数。
因此如果固定不变,那么答案也就固定不变,因此为了得到最小的改变次数,我们就需要改变。那么要改成什么数呢?对于原序列,我们先算出每一项所在公差为的等差数列的首项,即算出每一项的,然后开个哈希表统计的次数,假设最后统计出出现次数最多的数值,那么就把变成。这是因为如果把变成那么对于算出的项就不需要进行改变(因为),选择出现次数最多的意味着需要改变的项越小,这是典型的贪心思想。
需要注意的是,我们只统计正整数的,因为题目要求每个数都是正整数,如果某项算出的不是正整数,而只能是正整数,因此该项无论取什么都要改一次。
AC代码如下,时间复杂度为:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N = 1010; 5 6 int a[N]; 7 struct Node { 8 char c; 9 int x, val; 10 }; 11 12 int main() { 13 int n, m; 14 scanf("%d %d", &n, &m); 15 for (int i = 1; i <= n; i++) { 16 scanf("%d", a + i); 17 } 18 unordered_map<int, int> cnt; 19 cnt[a[1]]++; // 一开始a[1]本身出现一次 20 for (int i = 2; i <= n; i++) { 21 int t = a[i] - (i - 1) * m; 22 if (t > 0) cnt[t]++; // 只有正整数才统计 23 } 24 int x = a[1], maxv = 1; // 一开始默认不改变a[1] 25 for (auto &it : cnt) { 26 if (it.second > maxv) maxv = it.second, x = it.first; // 找到出现次数最多的数 27 } 28 vector<Node> ans; 29 for (int i = 1; i <= n; i++) { 30 int t = a[i] - (x + (i - 1) * m); // a[i]与x + (i - 1)*k的插值,如果等于0表示不需要改变 31 if (t > 0) ans.push_back({'-', i, t}); 32 else if (t < 0) ans.push_back({'+', i, -t}); 33 } 34 printf("%d\n", ans.size()); 35 for (auto &it : ans) { 36 printf("%c %d %d\n", it.c, it.x, it.val); 37 } 38 39 return 0; 40 }
再给出y总的做法。
首先容易发现答案最大为,因为每个数最多改变次,实际上还可以让固定,改变剩余的个数,因此答案最大值就变成了。因此现在最多改变次,意味着至少有一项是不会改变的,因此我们可以枚举每一项,固定该项,然后再枚举一遍序列进行比较,如果,那么就需要改变。通过枚举所有项就可以找到最小改变次数了。
AC代码如下,时间复杂度为:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N = 1010; 5 6 int a[N]; 7 struct Node { 8 char c; 9 int x, val; 10 }; 11 12 int main() { 13 int n, m; 14 scanf("%d %d", &n, &m); 15 for (int i = 1; i <= n; i++) { 16 scanf("%d", a + i); 17 } 18 vector<Node> ans; 19 for (int i = 1; i <= n; i++) { 20 vector<Node> vec; 21 for (int j = 1; j <= n; j++) { 22 int t = a[i] + (j - i) * m; 23 if (t <= 0) { // 每个数都要是正整数 24 vec.clear(); 25 break; 26 } 27 if (a[j] > t) vec.push_back({'-', j, a[j] - t}); 28 else if (a[j] < t) vec.push_back({'+', j, t - a[j]}); 29 } 30 if (!vec.empty() && (ans.empty() || ans.size() > vec.size())) ans = vec; 31 } 32 printf("%d\n", ans.size()); 33 for (auto &it : ans) { 34 printf("%c %d %d\n", it.c, it.x, it.val); 35 } 36 37 return 0; 38 }
参考资料
AcWing 4780. 等差数列(AcWing杯 - 周赛):https://www.acwing.com/video/4557/
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/17050962.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效