牛客练习赛51 E 数列

**这道题首先可以二分答案,也就是满足条件的下标个数,我们可以换种方式来理解他:数列中出现的断层数量,下图表示的就是样例中的情况,假使数列为直接的1-n序列,那答案显然是n-1,而如果其中每出现一个断层,则答案减一,而每个断层开始自然是1最优,因此我们需要确定的就是最少的断层数**


**那么为什么具有二分性呢,很显然,一个有x个断层的序列,那对于x+1个断层,我只要在原序列中随意一个断层中再断一次就能严格减小花费,因此二分是合理的**

**然后我们的check函数中要做的就是确定构成该数目断层需要的最少数字之和,那么这里又是很容易就能想到,最长的断层和最短的断层长度差值不会超过1,为什么?**
**如下图,有一个123412的数组,那我把4去掉之后在第二个2后面加一个3,断层数不变,但是总花费减小了,所以我们发现高的断层补低的断层可以减小花费,那么不断补之后的结果就是高度差小于等于1**

**所以对于当前的断层数,我们可以通过向下取整来求得较低的断层的高度,再取余解出较高的断层个数,加减乘除一下返回最小花费:**

```cpp
bool check(int x){
    int cnt=n/(x+1);//较低的高度
    int cct=n%(cnt*(x+1));//较高断层的个数
    int num=(x+1)*s[cnt]+cct*(cnt+1);//每个较高的断层,相当于在较低的断层后加了一列cnt+1,因此乘上个数再加上
    return num<=m;//判断合理性
}
```
**找到了最小断层数以后,就可以通过之前求解的高度和两种断层的个数直接输出了:**

```cpp
void solve(int x){
    int cnt=n/(x+1);//高度
    int cct=n%(x+1);
    int pos=0;
    for(int i=1;i<=cct;i++){//cct个较高断层
    for(int j=1;j<=cnt+1;j++){
        as[++pos]=j;
    }
}
    for(int i=1;i<=x+1-cct;i++){//x+1-cct个较低断层
        for(int j=1;j<=cnt;j++){
            as[++pos]=j;
        }
    }
    for(int i=1;i<=pos;i++){
        printf("%d",as[i]);if(i!=pos)printf(" ");
    }    
}
```
## 完整代码:https://ac.nowcoder.com/acm/contest/view-submission?submissionId=41228594



全部评论
%%%%%%,9f txdy
点赞 回复 分享
发布于 2019-09-07 08:31
%%%%%%%
点赞 回复 分享
发布于 2019-09-07 10:10

相关推荐

11-07 13:31
怀化学院 Java
勇敢牛牛不怕难:又疯一个
点赞 评论 收藏
分享
1 收藏 评论
分享
牛客网
牛客企业服务