CF803D Magazine Ad 题解

· · 题解

随机跳了一道题,就放在题库里,原以为是一道 dp,结果是到二分。

首先,我们必须要做的就是将难以处理的字符串转化为我们比较熟悉的数字,因为在所有的 -' '之间都可以断,所以我们将其中的字符串转化为一个数记为该段的长度。最后我们会得到一个长度为 n 的数组 val[i] ,而我们要将这 n 个数分成 k 段。

到这里,这道题就显然了。

n 个数分成 k 个区间,使最大区间和最小

我们直接二分区间长度,然后暴力该区间和满足需要多少段。

check(int len) 函数:

inline bool check(int x)
{
    int res=0,cnt=0;
    for(int i=1;i<=tot;++i)
    {
        if(val[i]>x) return 0;
        if(res+val[i]<=x) res+=val[i];
        else ++cnt,res=val[i];
    }
    // printf("%d %d\n",x,cnt); //调试用
    if(cnt>=k) return 0;
    return 1;
}

记得特判 val[i]>x 的情况(即单个区间的长度已经大于了需要判定的长度)

然后这道题就十分简单了。

有几个注意的点:

``` c++ 省略预处理部分 int k,len,p; char str[MAXS]; int val[MAXS],tot; inline bool check(int x) { int res=0,cnt=0; for(int i=1;i<=tot;++i) { if(val[i]>x) return 0; if(res+val[i]<=x) res+=val[i]; else ++cnt,res=val[i]; } // printf("%d %d\n",x,cnt); if(cnt>=k) return 0; return 1; } int main() { // freopen("dp.in","r",stdin); // freopen("dp.out","w",stdout); read(k); while((str[++len]=gh())!='\n'); p=1; for(int i=1;i<=len;++i) if(str[i]=='-'||str[i]==' ') val[++tot]=i-p+1,p=i+1; if(p!=len+1) val[++tot]=len-p; int l=0,r=len; while(l<r) { int mid=(l+r)>>1; if(check(mid)) r=mid; else l=mid+1; } printf("%d",l); return 0; } /* 4 garage for sa-le 7 4 3 2 4 Edu-ca-tion-al Ro-unds are so fun 4 3 5 3 3 5 4 3 3 */ ```