首页 > 其他分享 >Luogu_P10977(AcWing_299) Cut the Sequence 题解

Luogu_P10977(AcWing_299) Cut the Sequence 题解

时间:2024-09-25 19:13:39浏览次数:1  
标签:Cut cout Sequence int 题解 sum cin right tie

解题思路

考虑线性 dp。

首先如果存在 \(a_i>m\),那肯定不满足条件,输出 \(-1\)。

设 \(f_i\) 表示前 \(i\) 个数分成若干段,然后每段最大数之和,其中每段内的整数之和不超过 \(m\)。

\(f_i\) 肯定是由 \(f_j\)(\(1\le j<i\))转移过来的,也就是前 \(j\) 个数分好后再加上 \((j,i]\) 这一段,所以 \((j,i]\) 这一段需要满足 \(\sum\limits_{k=j+1}^{i}a_k\le m\),所以 \(j\) 就可以从 \(i-1\) 到 \(1\) 倒序枚举。

继而有转移方程:

\[f_i=\min_{j=1}^{i-1}\left\{\left[\sum_{k=j+1}^ia_k\le m\right]\times\max_{k=j+1}^i\left\{a_k\right\}\right\} \]

时间复杂度为 \(\mathcal{O}(n^2)\),得分 \(24\text{pts}\)。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, m, a[N], f[N];
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0), cout.tie(0);
  cin >> n >> m;
  for(int i = 1; i <= n; i++) {
    cin >> a[i];
  }
  memset(f, 0x3f, sizeof(f));
  f[0] = 0, f[1] = a[1];
  for(int i = 2; i <= n; i++) {
    int maxi = -1, sum = 0;
    for(int j = i - 1; j >= 1 && sum + a[j] <= m; j--) {
      sum += a[j];
      maxi = max(maxi, a[j + 1]);
      f[i] = min(f[i], f[j] + maxi);
    }
  }
  cout << f[n];
  return 0;
}

接着讲正解,单调队列优化 dp。

区间和可以用前缀和处理。

注意到 \(j\) 最小的时候满足 \(\sum\limits_{k=j+1}^ia_k\le m\),也就是说 \(\sum\limits_{k=j}^ia_k>m\),这个数可以单独处理,而 \(t=\max\limits_{k=j+1}^i\left\{a_k\right\}\) 可以通过单调队列存一个单调递减的最大值数列,但因为最后答案 \(f_j+t\) 不具有单调性,所以需要再存一个小根堆,建议用 multiset,因为每次删除时优先队列不好删除。

时间复杂度为 \(\mathcal{O}(n\log_2n)\)。

AC 代码,请勿抄袭

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, m, a[N], sum[N], f[N];
deque<int> dq;
multiset<int> s;
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0), cout.tie(0);
  cin >> n >> m;
  bool flag = 0;
  for(int i = 1; i <= n; i++) {
    cin >> a[i];
    flag |= (a[i] > m);
    sum[i] = sum[i - 1] + a[i];
  }
  if(flag) { return cout << "-1", 0; }
  int p = 0;
  for(int i = 1; i <= n; i++) {
    while(sum[i] - sum[p] > m) { ++p; }
    while(!dq.empty() && dq.front() <= p) {
      int tmp = dq.front();
      dq.pop_front();
      if(!dq.empty()) { s.erase(f[tmp] + a[dq.front()]); }
    }
    while(!dq.empty() && a[dq.back()] <= a[i]) {
      int tmp = dq.back();
      dq.pop_back();
      if(!dq.empty()) { s.erase(f[dq.back()] + a[tmp]); }
    }
    int tmp = (!dq.empty() ? dq.back() : 0);
    dq.push_back(i);
    f[i] = f[p] + a[dq.front()];
    if(dq.size() > 1) {
      s.insert(f[tmp] + a[i]);
      f[i] = min(f[i], *s.begin());
    }
  }
  cout << f[n];
  return 0;
}

标签:Cut,cout,Sequence,int,题解,sum,cin,right,tie
From: https://www.cnblogs.com/cyf1208/p/18432002

相关文章

  • 【OJ题解-1】稀疏矩阵乘法
    一、试题题面计算两个稀疏矩阵相乘,输出相乘的结果【输入输出约定】输入:第一行输入三个正整数p、q、r,表示p×q和q×r的两个矩阵相乘;(约定0<p,q,r≤1000)然后是第一个矩阵的输入,首先是一个整数m,表示矩阵一有m个非零元素;然后是m行,每行三个整数i,j,d,表示第i行,第j列的元素为d(约定......
  • P8906 [USACO22DEC] Breakdown P 题解
    P8906[USACO22DEC]BreakdownP题解显然的套路是删边转化为加边。考虑到维护整条路径不好维护,于是考虑转化维护\(f_{i,k},g_{i,k}\)分别表示\(1,n\)到\(i\)走了\(k\)步时的最短路。那么此时\(k\le4\)。我们先考虑\(f\)的转移,\(g\)的转移是等价的。那么对于\((......
  • 题解:CF573D Bear and Cavalry
    因为这是远古题目,所以根据现在的评测机速度,用\(O(nq)\)的做法也是可以过的。也就是说,我们可以每次操作直接修改对应位置上的数字,然后设计一种\(O(n)\)的算法求解答案。这道题类似资源分配型动态规划,所以我们可以设\(dp_i\)表示分配前\(i\)个人的答案。直接写是不行的,我......
  • 题解:AT_abc204_e [ABC204E] Rush Hour 2
    变形的dijkstra。先思考什么情况下需要等待以及等待多长时间最优。我们把题目上的计算方法按照当前的时间\(t\)和通过所需的时间\(f(t)\)列个函数关系:\[f(t)=t+c+\lfloor\frac{d}{t+1}\rfloor\]然后用Desmos画个图可以得到图像(其实就是对勾函数):因为\(c,d\geq0\),所......
  • [湖北省选模拟 2023] 棋圣 / alphago 题解
    很牛的题目啊。-Alex_Wei发现这个操作比较复杂但限制较弱,考虑通过考察“不变的量”来刻画操作。容易发现若为二分图,则初始颜色不同的一定不能移动到一起。又因为在存在环的图上这个限制很弱/目前较难考虑,所以先考虑树的情况,发现答案存在可能取到的上界,令\(c_{i,j}\)为初......
  • CF1119H Triple 题解
    DescriptionSK酱送给你了一份生日礼物。礼物是\(n\)个三元组\((a_i,b_i,c_i)\)和四个正整数\(x,y,z,k\)。你利用这\(n\)个三元组填充了\(n\)个数组,其中第\(i\)个数组中有\(x\)个\(a_i\),\(y\)个\(b_i\),\(z\)个\(c_i\)(所以第\(i\)个数组长度为\((x+y+z)\)。......
  • Codeforces Round 974 (Div. 3)题解记录
    A.RobinHelps签到模拟,遍历一遍即可,注意没钱时不给钱。\(O(n)\)#include<iostream>#include<set>#include<map>#include<vector>#include<algorithm>#include<bitset>#include<math.h>#include<string>#include<string.h>#......
  • [ARC122E] Increasing LCMs 题解
    感觉像比较套路的构造题。思路假如我们正着进行构造,可以发现我们加入一个数以后,对后面的数产生的影响是很大的。但是如果我们从最后一个数开始构造,那么可以发现它是不会对之后的构造产生任何影响的。应为越前面的数的限制会越少,那么可以填的数一定是不减的。一个数可以填在后......
  • 算法题之图论 [NOIP2001 提高组] Car的旅行路线详细题解
    P1027[NOIP2001提高组]Car的旅行路线这道题的思路呢,就是建个图,然后跑一遍Floyd,比较最小值就可以解决了。but!它每个城市只给三个点(共四个),所以还得计算出第四个点坐标。这里根据矩形的中点公式来表示未知点的坐标:(这个思路源于大佬 _jimmywang_       ......
  • [ARC121E] Directed Tree 题解
    简单容斥题。思路题面的条件相当于一个位置上填的点不能是自己的祖先。发现直接做并不好做。考虑容斥。我们想要求出\(f_i\)为至少有\(i\)个不合法位置的方案数。那么答案为:\[\sum_{i=0}^nf_i(-1)^i\]如何求解。设\(f_{i,j}\)为\(i\)子树下有\(j\)个不合法位......