2019蓝桥省赛B组编程题第3、4题题解(等差数列,后缀表达式)

14 篇文章 1 订阅
7 篇文章 0 订阅

等差数列

本题的考点为最大公因数 ( 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)(kp1p2...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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值