【每日一题】数学考试

数学考试

https://ac.nowcoder.com/acm/problem/15553

Statement

今天qwb要参加一个数学考试,这套试卷一共有道题,每道题qwb能获得的分数为,qwb并不打算把这些题全做完,他想选总共道题来做,并且期望他能获得的分数尽可能的大,他准备选个不连续的长度为的区间,即
其中有

Solution

把题意简单点说:将一个数组分成两个长度均为且不相交的子串,使得这两个子串的和最大。

那么令表示第个位置前面选了个这样的区间所能得到的最大值,那么就容易得到转移式:

上面的求和式子可以用前缀和优化成

其余情况则有

于是答案就是,而不是是因为这两个区间是一定要取的而不是想取个。即全体负数的情况下也要选两个负数区间最小的。

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void Main();
int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie();
  Main();
  return 0;
}

void Main() {
  int T; cin >> T;
  while(T--) {
    int n, k; cin >> n >> k;
    vector<int> a(n + 1, 0); // 获得分数
    vector<ll> pre(n + 1, 0); // 前缀和
    vector<vector<ll>> dp(n + 1, vector<ll>(3, -1e13)); // 动态规划数组
    for(int i = 1; i <= n; i++) {
      cin >> a[i];
      pre[i] = pre[i - 1] + a[i]; // 求前缀和
    }
    dp[0][0] = 0;
    for(int i = 1; i <= n; i++) {
      for(int j = 0; j < 3; j++) {
        dp[i][j] = dp[i - 1][j]; // 不以第i个数为结尾的区间能取到的最大值
      }
      if(i >= k) {
        // 与以第i个数为结尾的区间作为第一个区间能取到的最大值
        dp[i][1] = max(dp[i][1], dp[i - k][0] + pre[i] - pre[i - k]);
        // 与以第i个数为结尾的区间作为第二个区间能取到的最大值
        dp[i][2] = max(dp[i][2], dp[i - k][1] + pre[i] - pre[i - k]);
      }
    }
    cout << dp[n][2] << '\n';
  }
}
全部评论

相关推荐

03-28 14:34
中南大学 Java
网易互娱明天的笔试是在一天之内任意选时间作答,那不就等于说可以抄答案?那为什么要发笔试?美团也说不拿笔试卡人,那为什么要发笔试?觉得学生们很有时间是吗?&nbsp;还有那些笔试全A了没有进面的,笔试的意义到底在哪里?
no_work_no_life:网易互娱的笔试本来就很简单 美团的确实不按笔试刷人,但是笔试是捞人的重要依据,尤其对于双非学生……我一面的时候面试官直接说是看我笔试成绩还可以就把我捞起来了……
投递美团等公司6个岗位 >
点赞 评论 收藏
分享
Beeee0927:正确的建议
点赞 评论 收藏
分享
生命诚可贵:先不说内容怎么样 排版就已经太差劲了 第一眼看不到重点,第二眼已经没有再看的耐心了, 篇幅占的太满了 字体不要用灰色 观感不好 想重点突出的黑色加粗就可以了 多列要点 少些大段的句子 项目经历把项目用的技术要点列出来,光写个python plc什么的太宽泛了 自我评价也有点偏多
点赞 评论 收藏
分享
评论
5
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务