P4447 [AHOI2018初中组]分组

P4447 [AHOI2018初中组]分组

贪心

原本考虑一口气连到底,但是只有60

举个反例: 1 2 3 3 4 5

一口气连到底的话就会出现:(1 2 3 4 5)(3),但最优解为(1 2 3)(3 4 5)

正解:

①考虑: 。。。6 6 7 7 7 。。。

‘6’有2个,‘7’有3个

所以最优方案中一定会出现一个‘7’开头的组:(7 。。)

碰到这种情况直接开一个新组

②考虑:。。。 6 6 6 7 7 。。。

‘6’有3个,‘7’有2个

所以最优方案中一定会出现一个‘6’结尾的组:(。。6 )

已知目前到‘6’为止(。。。6 6 6)的最优解一定有3个以‘6’结尾的组

我们把较短的两组各加上一个‘7’,这样就达成让最短的组尽量长的目的

 

用两个数组分别储存各组的长度和末尾元素

对所有元素从小到大排序

每次添加元素时找到最短的可以连上的组就可以了

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,a[100005],l=1,r,b[100005],lb[100005];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    for(int i=1;i<=n;++i){
        int p=0;
        for(int j=r;j>=l;--j){
            if(b[j]+1<a[i]) l=j+1; //优化
            if(b[j]+1==a[i]){ //在所有可以连上的组中,后开的组长度一定比较短
                ++b[j]; ++lb[j];
                p=1; break;
            }
        }
        if(!p) b[++r]=a[i],++lb[r];
    }
    int M=1e9;
    for(int i=1;i<=r;++i)
        M=M<lb[i]?M:lb[i]; //找最短长度
    printf("%d",M);
    return 0;
}

 

 

posted @ 2021-07-06 21:38  kafuuchino  阅读(101)  评论(0编辑  收藏  举报