2 条题解

  • 0
    @ 2025-11-8 21:21:27
    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N = 1e6+5;
    int a[200100], l[200100], r[200100], he[200100];
    void solve() {
        int n, m, v;
        cin >> n >> m >> v;
        for(int i = 1; i <= n; i++){
            cin >> a[i];
        }
        l[0] = 0;
        int sum = 0;
        // 该代码是求从1到n,满足美味值大于v的人数
        // 例如,此时l[i]的值为3,那就代表从1到i有3个人满足分到蛋糕的美味值大于v
        for(int i = 1; i <= n; i++)
        {
            l[i] = l[i - 1];
            sum += a[i];
            if (sum >= v){
                l[i]++;
                sum = 0;
            }
        }
        sum = 0;
        r[n + 1] = 0;
        // 与l代表的意义一样,之所以从n到1,是因为最终的答案肯定是一个区间和
        // 假如是[L,R],那整个n就被分为三部分[1,L-1],[L,R],[R+1,n],由于不清楚R+1,所以我们没法从R+1到n
        // 但是我们可以从n到R+1,那为什么不直接用之前的l数组呢?
        // 那是因为他们两个中间隔着[L,R],而l数组记录了[L,R],会对之后的数据产生影响
        for(int i = n; i >= 1; i--)
        {
            r[i] = r[i + 1];
            sum += a[i];
            if (sum >= v) {
                r[i]++;
                sum = 0;
            }
        }
        he[0] = 0;//前缀和,用于计算最终答案。
        for (int i = 1; i <= n; i++) {
            he[i] = he[i - 1] + a[i];
        }
        int ans = -1;
        //因为从1到n,美味值至少为v的人数达到m,所以最终答案的值不为-1。
        if (l[n] >= m) {
            ans = 0;
        }
        // 开始遍历区间[L,R],这种方法叫双指针,可以去学一学
        // 先固定右端点r1,移动左端点l1,当左端点大于右端点时,我们把此时的右端点移到左端点。
        int r1 = 1, l1 = 1;
        for (l1 = 1; l1 <= n; l1++) {
            if (l1 > r1){
                r1 = l1;
            }
            //前提条件成立,开始求最大值(通过移动右端点),直到前提条件不符合。
            while (l[l1 - 1] + r[r1 + 1] >= m && r1 <= n) {
                ans = max(ans, he[r1] - he[l1 - 1]);
                r1++;
            }
        }
        cout << ans << '\n';
    }
    signed main() {
        ios::sync_with_stdio(0);
        cin.tie(0), cout.tie(0);
        int T = 1;
        cin >> T;
        while (T--) solve();
        
        return 0;
    }
    
    • 0
      @ 2025-11-8 21:05:10

      这道题不难想到,最终的答案肯定是一个区间和,由于我们要在保证软件ACM成员都开心的情况的条件下,保证自己的最多,那既然最多,其他成员的美味值就恰好为v,或者第一次大于v的时候就停止分,这样确保lfq分到的是最多的,我们可以分为三个区间,lfq分在[L,R]中的蛋糕,那剩余的[1,L-1],[R+1,n]的值的和要>=m,于是就有下面的代码
      #include <bits/stdc++.h>
      using namespace std;
      long long a[200100], l[200100], r[200100], he[200100];
      int main()
      {
      int t;
      scanf("%d", &t);
      for (int i = 1; i <= t; i++)
      {
      int n, m, v;
      scanf("%d%d%d", &n, &m, &v);
      for (int i = 1; i <= n; i++)
      {
      scanf("%lld", &a[i]);
      }
      l[0] = 0;
      long long sum = 0;
      for (int i = 1; i <= n; i++)//该代码是求从1到n,满足美味值大于v的人数,例如,此时l[i]的值为3,那就代表从1到i有3个人满足分到蛋糕的美味值大于v
      {
      l[i] = l[i - 1];
      sum += a[i];
      if (sum >= v)
      {
      l[i]++;
      sum = 0;
      }
      }
      sum = 0;
      r[n + 1] = 0;
      for (int i = n; i >= 1; i--)//与l代表的意义一样,之所以从n到1,是因为最终的答案肯定是一个区间和,假如是[L,R],那整个n就被分为三部分[1,L-1],[L,R],[R+1,n],由于不清楚R+1,所以我们没法从R+1到n,但是我们可以从n到R+1,那为什么不直接用之前的l数组呢?那是因为他们两个中间隔着[L,R],而l数组记录了[L,R],会对之后的数据产生影响
      {
      r[i] = r[i + 1];
      sum += a[i];
      if (sum >= v)
      {
      r[i]++;
      sum = 0;
      }
      }
      he[0] = 0;//前缀和,用于计算最终答案。
      for (int i = 1; i <= n; i++)
      {
      he[i] = he[i - 1] + a[i];
      }
      long long ans = -1;
      if (l[n] >= m)//因为从1到n,美味值至少为v的人数达到m,所以最终答案的值不为-1。
      {
      ans = 0;
      }
      int r1 = 1;//开始遍历区间[L,R],这种方法叫双指针,可以去学一学,先固定右端点r1,移动左端点l1,当左端点大于右端点时,我们把此时的右端点移到左端点。
      int l1 = 1;
      for (l1 = 1; l1 <= n; l1++)
      {
      if (l1 > r1)
      {
      r1 = l1;
      }
      while (l[l1 - 1] + r[r1 + 1] >= m && r1 <= n)//前提条件成立,开始求最大值(通过移动右端点),直到前提条件不符合。
      {
      ans = max(ans, he[r1] - he[l1 - 1]);
      r1++;
      }
      }
      printf("%lld\n", ans);
      }
      return 0;
      }

      • 1

      信息

      ID
      1188
      时间
      1000ms
      内存
      256MiB
      难度
      10
      标签
      递交数
      12
      已通过
      2
      上传者