P1182 数列分段 Section II【题解】

做法:贪心+二分

题意解读:

这题是我发的上一篇题解的题目的升级版。大意为给定一个长度为 N N N序列 a i ( i ∈ [ 1 , N ] , i ∈ N ∗ ) a_i(i\in[1,N],i\in\mathbb N^*) ai(i[1,N],iN),将其分成 M M M段,要求每段连续,并且使每段和的最大值最小

相信大家如果眼睛不瞎 ( L J Z : 我 瞎 呢 ) (LJZ:我瞎呢) (LJZ:)都能看到上面加粗的五个字:最大值最小。当题目中出现了类似的字眼时,就表示大概率这题的答案具有单调性,可以二分解决。 ( O W : 今 年 t g 必 考 二 分 ) (OW:今年tg必考二分) (OW:tg)

思路:

我们设这个最小值为 K K K。我们略加思考可以发现:当 K K K十分的小时,一定可以存在一种分组,使组数 M K > M ( 举 个 例 子 : 每 个 数 自 成 一 组 。 ) M_K>M(举个例子:每个数自成一组。) MK>M,此时的 K K K值都是符合题意的。而当 K K K逐渐增长到一个临界点以后, M K M_K MK将小于 M M M,此时的 K K K都不符合题意。所以这个临界点 ( 设 为 K 0 ) (设为K_0) (K0)满足:
{ ∀ M x ∈ [ 1 , M 0 ] , M 均 符 合 题 意 。 ∀ M x ∈ ( M 0 , + ∞ ] , M 均 不 符 合 题 意 。 \begin{cases} \forall M_x\in[1,M_0],M均符合题意。\\ \forall M_x\in(M_0,+\infty],M均不符合题意。 \end{cases} { Mx[1,M0],MMx(M0,+],M
受到这个 M 0 M_0 M0性质的启发,我们定义函数:

C ( x ) = { 0 , x > M 0 1 , x ≤ M 0 C(x)=\begin{cases} 0,x>M_0\\ 1,x\leq M_0 \end{cases} C(x)={ 0,x>M01,xM0
然后取
l = x m i n = max ⁡ ( a i ) , 即 M = n 。 r = x m a x = s u m ( a i ) , 即 M = 1 。 l=x_{min}=\max(a_i),即M=n。\\r=x_{max}=sum(a_i),即M=1。 l=xmin=max(ai)M=nr=xmax=sum(ai)M=1

二分求出临界值即可。

A C c o d e AC code ACcode:

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

int n, m, a[100005],l,r;
long long s[100005];

inline void read()
{
    
     
    cin >> n >> m;
    for (int i = 1; i <= n;i++)
    {
    
    
        cin >> a[i];
        l = max(a[i], l);
        r += a[i];
    }
}

inline bool C(int x)
{
    
    
    int tot=0,num=0;
    for(int i=1;i<=n;i++)
    {
    
    
        if(tot+a[i]<=x)tot+=a[i];
        else tot=a[i],num++;
    }
    return num>=m;
}

int main()
{
    
    
    read();
    while(l<=r)
    {
    
    
        int mid=(l+r)>>1;
        if(C(mid))
        {
    
    
            l = mid+1;
        }
        else
        {
    
    
            r = mid-1;
        }
    }
    cout << l << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_62444770/article/details/120589221