题解
- 一看题目,要我们求最大值最小,显然二分
- 设二分出一个t表示分班后的最大的女友指数,显然后面划分出来的所有班都要小于t
- 那么现在问题转换为求这样分班后是否可行
- 题目还有一个条件:所有班的欠扁值之和不得超过Limit
- 考虑一下dp
- 设f[i]为分班到第i位的最小欠扁值和
- f[i]=min(f[j]+max(h[j]...h[i]),f[i])且

- 这公式显然可以推出来
- 这样的话时间复杂度就是O(n log n^2),显然会炸
- 这样的话,考虑再二分出分组的界线,用前缀和sum[i]表示前i个人的g[i]的和
- 对于欠扁值的话,也就是在区间里取最大值
代码
1 #include <cstdio>
2 #include <iostream>
3 #include <cstring>
4 #include <algorithm>
5 using namespace std;
6 const int inf=10000000000;
7 int n,limit,h[20010],g[20010],sum[20010],last[20010],f[20010],z[20010],x[20010],tot,l,r,mid;
8 bool check(int x)
9 {
10 int l,r,mx,ans,mid;
11 memset(f,127,sizeof(f));
12 f[1]=0;
13 for (int i=1;i<=n;i++)
14 {
15 l=i; r=n;
16 while (l<r)
17 {
18 mid=(l+r)/2;
19 if (sum[mid]-sum[i-1]<=x) l=mid+1; else r=mid;
20 }
21 if (sum[r]-sum[i-1]<=x) r++;
22 ans=0; l=i; mx=0;
23 while (l<r)
24 {
25 ans+=g[l];
26 f[l]=min(f[l],f[i]+mx);
27 mx=h[l]; l=last[l];
28 }
29 f[r]=min(f[r],f[i]+mx);
30 }
31 if (f[n+1]<=limit) return true; else return false;
32 }
33 int main()
34 {
35 scanf("%d%d",&n,&limit);
36 for (int i=1;i<=n;i++)
37 {
38 scanf("%d%d",&h[i],&g[i]);
39 sum[i]=sum[i-1]+g[i];
40 }
41 z[1]=inf; x[1]=n+1; tot=1;
42 for (int i=n;i>=1;i--)
43 {
44 while (h[i]>=z[tot]) tot--;
45 last[i]=x[tot];
46 tot++;
47 z[tot]=h[i]; x[tot]=i;
48 }
49 l=1,r=sum[n];
50 while (l<r)
51 {
52 mid=(l+r)/2;
53 if (check(mid)) r=mid; else l=mid+1;
54 }
55 printf("%d",l);
56 }