等差数列
本题的考点为最大公因数 ( G C D ) (GCD) (GCD)的求法 (即辗转相除法(如有需求请自行百度))。
由于 A 1 A_1 A1~ A n A_n An 不一定是按等差数列顺序给出,所以需要排序 ( s o r t ( ) sort(~) sort( ))。
想求包含 n n n 个元素的最短等差数列,就要使公差最大。
对于所有两两元素之间的差求最大公因数,该数即为该等差数列的最大公差。
有了最大公差,就好求出最小长度了。
注意特判差为 0 0 0 的情况。
#include <bits/stdc++.h>
using namespace std;
int n;
int d;
long long a[100005];
long long gcd(long long a, long long b) { return b == 0 ? a : gcd(b, a % b); }
int main() {
scanf("%d", &n);
for (int i = 0; i < n; i++) scanf("%lld", &a[i]);
sort(a, a + n);
d = a[1] - a[0];
for (int i = 2; i < n; i++) d = gcd(d, a[i] - a[i - 1]);
if (d)
printf("%lld", (a[n - 1] - a[0]) / d + 1);
else
printf("%d", n);
return 0;
}
后缀表达式
常规情况先按下不表。我们讲讲特殊的:
-
当正数多而加号少时,可以将式子构造成以下形式来提高数值:
设 p p p为正数, k k k 为一个非正数, f ( x ) f(x) f(x) 为其他数和操作符组成的式子, f ( x ) − ( k − p 1 − p 2 − . . . − p n ) f(x)-(k-p_1-p_2-...-p_n) f(x)−(k−p1−p2−...−pn)
-
同理,当负数多而减号少时我们可以构造:
设 q q q 为负数, f ( x ) f(x) f(x) 为其他数和操作符组成的式子, f ( x ) − ( q 1 + q 2 + . . . + q n ) f(x)-(q_1+q_2+...+q_n) f(x)−(q1+q2+...+qn)
只要想清楚这两种情况,问题就迎刃而解了:
-
按常规情况将第一个数和加号分配给正数或 0 0 0,将减号分配给负数,剩下多余出来的都可以凑成以上两个式子的形式:多减号可以添 0 0 0 或者从前方配一个负数为上式的 k k k ,多加号可以从前方调一个减号配成上述式子,而 0 0 0 可以自由分配 )。
-
而当出现减号且全正数 ( 即没有 0 0 0 或负数作 k k k ) 时,只要对所有值贪心取最小值作为减去的 k k k 。
-
而当出现全负数 ( 即没有 0 0 0 或正数作 f ( x ) f(x) f(x) 式中的第一个数 ) 时,只要对所有值贪心取最大值 (记住是负数) 为第一个数,而其他数对答案的贡献本身的绝对值。
-
原本以为要用数据结构或 S T L STL STL,但是最后想破头发现贪心就可以完成。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll negsum = 0, possum = 0;
ll n, m, a, minn = 1e9 + 7, maxn = -(1e9 + 7);
ll ans = 0;
bool hasZero = false;
int main() {
cin >> n >> m;
for (int i = 0; i < n + m + 1; ++i) {
cin >> a;
if (a < 0) {
negsum += a; // 负数中找最大数
maxn = max(maxn, a);
} else {
possum += a;
if (a == 0)
hasZero = true;
else // 正数中找最小数
minn = min(minn, a);
}
}
ans += possum; // 原本在possum中加过minn 所以减两个minn
if (m && !hasZero && !negsum) ans -= (minn << 1);
if (m) {
ans -= negsum; // 同上
if (!hasZero && !possum) ans += (maxn << 1);
} else
ans += negsum;
cout << ans;
return 0;
}