欢迎光临
我们一直在努力

数学考试【牛客tracker & 每日一题】

数学考试

时间限制:1 秒 空间限制:64M

网页链接

牛客tracker

牛客tracker & 每日一题,完成每日打卡,即可获得牛币。获得相应数量的牛币,能在【牛币兑换中心】,换取相应奖品!助力每日有题做,丰盈牛币日益多! 在这里插入图片描述


题目描述

牛妹参加了 2022 年普通高校全牛世界招生统一考试。数学试题太难,她决定复读。

为了在考试中取得更好的成绩,牛妹决定对数学进行特训。特训练习共

n

n

n 道题,第

i

i

i 题的难度为

a

i

a_i

ai​,分值为

b

i

b_i

bi​。为了更好提高自己的数学水平,牛妹决定按照题目顺序做题。

做题会对牛妹的压力指数

P

P

P 产生影响。牛妹在长期磨练中养成了一颗大心脏,做完第

i

i

i 题后,牛妹可以选择保持自己的压力指数

P

P

P 不变、使

P

P

P 增加

Q

i

Q_i

Qi​ 或使

P

P

P 减少

W

i

W_i

Wi​。压力指数上限为

K

K

K,下限为

0

0

0。如果

P

P

P 增加

Q

i

Q_i

Qi​ 后大于

K

K

K,牛妹就不可以选择让自己的压力指数增加

Q

i

Q_i

Qi​;同理,如果

P

P

P 减少

W

i

W_i

Wi​ 后小于

0

0

0,牛妹就不可以选择让自己的压力指数减少

W

i

W_i

Wi​。

牛妹相信压力可以转化为动力。当牛妹在压力为

P

P

P 的状态下完成第

i

i

i 题时,她一定可以做对这一题,并可以积累

a

i

×

P

a_i \\times P

ai​×P 的经验。但压力太大会反噬牛妹,当

P

>

b

i

P > b_i

P>bi​ 时,牛妹不能做对第

i

i

i 题,无法积累任何经验。请注意,无论是否做对,都算作完成了第

i

i

i 题,在做完后,才更改压力值。

牛妹想要知道,完成本次数学特训后,她最多可以积累多少经验。牛妹初始的压力值可以由牛妹在

0

−

K

0 – K

0−K 范围内自由选定。

请注意,本题的空间限制较为特别,仅有 64MB。


输入描述

输入共

n

+

1

n + 1

n+1 行。

  • 输入的第一行为两个正整数

    n

    ,

    K

    n, K

    n,K,

    1

    ≤

    n

    ≤

    10

    4

    1 \\le n \\le 10^4

    1≤n≤104,

    1

    ≤

    K

    ≤

    5

    ×

    10

    3

    1 \\le K \\le 5 \\times 10^3

    1≤K≤5×103。

  • 接下来

    n

    n

    n 行,每行四个正整数,第

    i

    +

    1

    i + 1

    i+1 行分别为

    a

    i

     

    (

    1

    ≤

    a

    i

    ≤

    10

    2

    )

    a_i\\ (1 \\le a_i \\le 10^2)

    ai​ (1≤ai​≤102),

    b

    i

     

    (

    1

    ≤

    b

    i

    ≤

    10

    9

    )

    b_i\\ (1 \\le b_i \\le 10^9)

    bi​ (1≤bi​≤109),

    Q

    i

     

    (

    1

    ≤

    Q

    i

    ≤

    K

    )

    Q_i\\ (1 \\le Q_i \\le K)

    Qi​ (1≤Qi​≤K),

    W

    i

     

    (

    1

    ≤

    W

    i

    ≤

    K

    )

    W_i\\ (1 \\le W_i \\le K)

    Wi​ (1≤Wi​≤K)。


输出描述

输出共一行,为牛妹可以积累经验的最大值。


示例 1

输入:

4 10
1 100 1 1
2 100 1 1
3 100 1 1
4 100 1 1

输出:

100


数据范围与提示

  • 1

    ≤

    n

    ≤

    10

    4

    1 \\le n \\le 10^4

    1≤n≤104,

    1

    ≤

    K

    ≤

    5

    ×

    10

    3

    1 \\le K \\le 5 \\times 10^3

    1≤K≤5×103

  • 1

    ≤

    a

    i

    ≤

    10

    2

    1 \\le a_i \\le 10^2

    1≤ai​≤102,

    1

    ≤

    b

    i

    ≤

    10

    9

    1 \\le b_i \\le 10^9

    1≤bi​≤109,

    1

    ≤

    Q

    i

    ,

    W

    i

    ≤

    K

    1 \\le Q_i, W_i \\le K

    1≤Qi​,Wi​≤K

  • 核心思路:动态规划 + 滚动数组。
  • 设

    d

    p

    [

    p

    ]

    dp[p]

    dp[p] 表示做完全部前若干题、当前压力为

    p

    p

    p 时可积累的最大经验。初始时因压力可自由选定,

    d

    p

    [

    p

    ]

    =

    0

    dp[p] = 0

    dp[p]=0 对所有

    p

    ∈

    [

    0

    ,

    K

    ]

    p \\in [0, K]

    p∈[0,K] 成立。

  • 处理第

    i

    i

    i 题时,先用本题的收益更新:

    d

    p

    ′

    [

    p

    ]

    =

    d

    p

    [

    p

    ]

    +

    {

    a

    i

    ×

    p

    ,

    p

    ≤

    b

    i

    0

    ,

    p

    >

    b

    i

    dp'[p] = dp[p] + \\begin{cases} a_i \\times p, & p \\le b_i \\\\ 0, & p > b_i \\end{cases}

    dp′[p]=dp[p]+{ai​×p,0,​p≤bi​p>bi​​ 再考虑“做完后修改压力”,即新状态

    p

    p

    p 可以由上一题的

    p

    p

    p(不变)、

    p

    −

    Q

    i

    p – Q_i

    p−Qi​(增加压力)、

    p

    +

    W

    i

    p + W_i

    p+Wi​(减少压力)转移而来,注意转移来源需满足

    p

    −

    Q

    i

    ≥

    0

    p – Q_i \\ge 0

    p−Qi​≥0 与

    p

    +

    W

    i

    ≤

    K

    p + W_i \\le K

    p+Wi​≤K 的合法性。

  • 最终答案为

    max

    ⁡

    0

    ≤

    p

    ≤

    K

    d

    p

    [

    p

    ]

    \\max_{0 \\le p \\le K} dp[p]

    max0≤p≤K​dp[p]。

  • 空间复杂度

    O

    (

    K

    )

    O(K)

    O(K),时间

    O

    (

    n

    K

    )

    =

    5

    ×

    10

    7

    O(nK) = 5 \\times 10^7

    O(nK)=5×107,刚好适配 64MB 的严格空间限制(不可开二维数组)。

  • 经验最大值可达

    100

    ×

    5000

    ×

    10

    4

    =

    5

    ×

    10

    9

    100 \\times 5000 \\times 10^4 = 5 \\times 10^9

    100×5000×104=5×109,需使用 64 位整数(long long)存储。

解题思路

本题是动态规划 + 滚动数组优化的经典问题。牛妹按顺序做题,每道题有一个难度

a

i

a_i

ai​、阈值

b

i

b_i

bi​、压力增加量

Q

i

Q_i

Qi​ 和压力减少量

W

i

W_i

Wi​。压力

P

P

P 的初始值可在

[

0

,

K

]

[0, K]

[0,K] 内自由选择。每做完一题,若当前压力

P

≤

b

i

P \\le b_i

P≤bi​,则获得

a

i

×

P

a_i \\times P

ai​×P 的经验,否则获得

0

0

0 经验;之后可以选择保持压力、增加

Q

i

Q_i

Qi​ 或减少

W

i

W_i

Wi​(需满足压力始终在

[

0

,

K

]

[0, K]

[0,K] 内)。目标是最大化总经验。

由于

n

≤

10

4

n \\le 10^4

n≤104,

K

≤

5000

K \\le 5000

K≤5000,状态数为

O

(

K

)

O(K)

O(K),但直接开二维数组会超出 64MB 空间限制,因此必须使用滚动数组,只保留上一题结束后的压力状态。

1. 问题等价转化
  • 设 dp[p] 表示处理完当前题目后,压力值为

    p

    p

    p 时能积累的最大经验。

  • 初始时,牛妹可以自由选择初始压力,因此对于所有

    p

    ∈

    [

    0

    ,

    K

    ]

    p \\in [0, K]

    p∈[0,K],dp[p] = 0。

  • 对于每道题

    (

    a

    i

    ,

    b

    i

    ,

    Q

    i

    ,

    W

    i

    )

    (a_i, b_i, Q_i, W_i)

    (ai​,bi​,Qi​,Wi​):

  • 计算本题经验:对于每个可达的压力

    p

    p

    p,若

    p

    ≤

    b

    i

    p \\le b_i

    p≤bi​,则本题获得经验

    a

    i

    ×

    p

    a_i \\times p

    ai​×p;否则获得

    0

    0

    0。将经验累加到当前状态上,得到临时值 c = dp[p] + (p <= b_i ? a_i * p : 0)。

  • 选择压力变化:做完本题后,牛妹可以选择压力不变、增加

    Q

    i

    Q_i

    Qi​ 或减少

    W

    i

    W_i

    Wi​(需满足新压力在

    [

    0

    ,

    K

    ]

    [0, K]

    [0,K] 内)。用临时值 c 更新新压力对应的状态:

    • 压力不变:new_dp[p] = max(new_dp[p], c)
    • 增加压力:若

      p

      +

      Q

      i

      ≤

      K

      p + Q_i \\le K

      p+Qi​≤K,则 new_dp[p + Q_i] = max(new_dp[p + Q_i], c)

    • 减少压力:若

      p

      −

      W

      i

      ≥

      0

      p – W_i \\ge 0

      p−Wi​≥0,则 new_dp[p – W_i] = max(new_dp[p – W_i], c)

  • 处理完所有题目后,答案即为 max(dp[0..K])。
2. 算法实现
  • 读入

    n

    ,

    K

    n, K

    n,K。

  • 创建两个长度为

    K

    +

    1

    K+1

    K+1 的 long long 数组 f 和 g,f 初始全为

    0

    0

    0(表示初始状态任意压力经验均为

    0

    0

    0),g 用于暂存下一状态。

  • 对于每道题:
    • 读入

      a

      ,

      b

      ,

      q

      ,

      w

      a, b, q, w

      a,b,q,w。

    • 将 g 全部置为

      −

      1

      -1

      −1(表示该状态尚未被更新,也可用极小值)。

    • 遍历压力

      x

      x

      x 从

      0

      0

      0 到

      K

      K

      K:

      • 令 c = f[x]。
      • 若

        x

        ≤

        b

        x \\le b

        x≤b,则 c += a * x。

      • 更新 g[x] = max(g[x], c)。
      • 若

        x

        +

        q

        ≤

        K

        x + q \\le K

        x+q≤K,更新 g[x + q] = max(g[x + q], c)。

      • 若

        x

        −

        w

        ≥

        0

        x – w \\ge 0

        x−w≥0,更新 g[x – w] = max(g[x – w], c)。

    • 将 f 与 g 交换(或 f = g)。
  • 遍历 f[0..K],取最大值输出。
  • 3. 复杂度分析
    • 时间复杂度:每道题需要遍历

      K

      +

      1

      K+1

      K+1 个压力状态,共

      n

      n

      n 道题,总复杂度

      O

      (

      n

      K

      )

      =

      10

      4

      ×

      5000

      =

      5

      ×

      10

      7

      O(nK) = 10^4 \\times 5000 = 5 \\times 10^7

      O(nK)=104×5000=5×107 次操作,在 1 秒内可以完成。

    • 空间复杂度:仅使用两个长度为

      K

      +

      1

      K+1

      K+1 的数组,空间为

      O

      (

      K

      )

      O(K)

      O(K),远小于 64MB 限制。

    总结

    通过滚动数组将二维 DP 压缩为一维,每次用上一题的状态推导当前题的状态。核心在于先计算本题经验,再决策压力变化。初始压力自由选择,因此初始 DP 全为

    0

    0

    0。注意使用 long long 防止经验值溢出。

    代码简要说明

    • 数组 f 和 g:f 存储上一轮结束后的最优经验,g 用于生成新一轮状态。
    • 循环处理每道题:
      • fill(g.begin(), g.end(), -1) 重置 g。
      • 遍历所有可能的压力 x,计算本题经验 c。
      • 分别更新压力不变、增加、减少三种情况到 g 中。
      • f.swap(g) 交换数组,进入下一题。
    • 输出:遍历 f 取最大值即为答案。

    代码内容

    #include <bits/stdc++.h>
    using namespace std;

    #define endl '\\n'
    typedef long long ll;
    typedef unsigned long long ull;
    typedef vector<vector<ll>> vvt;
    typedef pair<ll,ll> pll;
    const ll N=1e3+10;
    const ll INF=1e18;
    const ll M=1e6+10;
    const ll mod=1e9+7;

    int main()
    {
    ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);
    ll n,k;
    cin>>n>>k;
    vector<ll> f(k+1,0),g(k+1,0);
    for(ll i=0;i<n;i++)
    {
    ll a,q,w;
    ll b;
    cin>>a>>b>>q>>w;
    fill(g.begin(),g.end(),–1);
    for(ll x=0;x<=k;x++)
    {
    ll c=f[x];
    if(x<=b) c+=a*x;
    if(c>g[x]) g[x]=c;
    ll y=x+q;
    if(y<=k&&c>g[y]) g[y]=c;
    y=x–w;
    if(y>=0&&c>g[y]) g[y]=c;
    }
    f.swap(g);
    }
    ll ans=0;
    for(ll p=0;p<=k;p++) if(f[p]>ans) ans=f[p];
    cout<<ans<<'\\n';
    return 0;
    }

    赞(0)
    未经允许不得转载:171主机测评 » 数学考试【牛客tracker & 每日一题】
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址