• 【每日一题】3.数学考试 (前缀和,线性DP)


    题目链接:Here

    思路:区间求和问题可以想到一个常用算法。前缀和。区间 ([l,r]) 的和可以用 (sum_r - sum_l) 方便求出

    由于区间长度 (k) 已知,所以我们可以直接选择暴力枚举两个区间的起点然后利用前缀和快速求和。

    具体细节如下:

    直接从 (k) 出发,用 cnt 比较出 (k) 之前最大区间和,用 ans 比较出 (k) 之后的最大区间和

    • 时间复杂度:(mathcal{O}(N))

    注意点:数据范围较大,注意使用 long long

    using ll = long long;
    using namespace std;
    int main() {
        ios_base::sync_with_stdio(false), cin.tie(0);
        int _;
        for (cin >> _; _--;) {
            int n, k;
            cin >> n >> k;
            vector<ll> a(n + 2);
            for (int i = 1; i <= n; ++i) cin >> a[i], a[i] = a[i - 1] + a[i];
            ll ans = -1e18, cnt = -1e18;
            for (int i = k; i + k <= n; ++i) {
                cnt = max(cnt, a[i] - a[i - k]);
                ans = max(ans, cnt + a[i + k] - a[i]);
            }
            cout << ans << "
    ";
        }
        return 0;
    }
    

    当然这道题不仅仅是枚举起点一种解法,也可以用线性 DP

    在我们预处理完前缀和后,如何获得某个位置之和的最大区间呢?我们可用线性 (DP) 求得,设 (f1_i) 表示位置 (i) 之前的最大区间和,而 (f2_i) 表示 (i) 之后的最大区间和。

    • (f1_i = max(f1_{i - 1} , sum_i - sum_{i - k}))
    • (f2_i = max(f2_{i + 1},sum_{i + k - 1} - sum_{i - 1}))
    using ll = long long;
    using namespace std;
    const int N = 2e5 + 10;
    ll f1[N], f2[N];
    int main() {
        ios_base::sync_with_stdio(false), cin.tie(0);
        int _;
        for (cin >> _; _--;) {
            int n, k;
            cin >> n >> k;
            vector<int> a(n + 1);
            vector<ll> sum(n + 1, 0);
            for (int i = 1; i <= n; ++i) {
                cin >> a[i];
                sum[i] = a[i] + sum[i - 1];
            }
            memset(f1, -127, sizeof f1);
            memset(f2, -127, sizeof f2);
            for (int i = k; i <= n - k; ++i)
                f1[i] = max(sum[i] - sum[i - k], f1[i - 1]);
            for (int i = n - k + 1; i >= k + 1; --i)
                f2[i] = max(sum[i + k - 1] - sum[i - 1], f2[i + 1]);
            ll ans = -1e18;
    
            for (int i = k; i <= n - k; ++i)
                ans = max(ans, f1[i] + f2[i + 1]);
            cout << ans << "
    ";
        }
        return 0;
    }
    

    最后是不是感觉代码二是代码一的详细版本?

    本质上两个代码是一样的(代码一在空间上更优),这里只是稍微展开来。

    The desire of his soul is the prophecy of his fate
    你灵魂的欲望,是你命运的先知。

  • 相关阅读:
    拜访优达学城上海总部
    ipad pro 文章
    探寻阿里云服务器迈入2.0时代的技术要点
    体验阿里云SSD云盘+ECS(I/O优化)的性能
    在iOS中使用OpenSSL的Public Key 进行加密
    使用FIR.im发布自己的移动端APP
    使用AFNetWorking 实现以Basic Authentication方式获取access-token
    使用AFNetWorking读取JSON出现NSCocoaErrorDomain Code=3840的解决方法
    #听云博客大赛#如何在自己的App嵌入听云产品监控App性能
    给自己的XTC820摆拍一下。
  • 原文地址:https://www.cnblogs.com/RioTian/p/14629297.html
Copyright © 2020-2023  润新知