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; }