洛谷 P4447 [AHOI2018 初中组] 分组 题解

蒟蒻的思路

这题是个贪心。于是手玩几个样例,看看能找到什么很有用的性质。我们先约定实力值为 \(l\sim r\) 的小组记作 \(G_r^l~(l\le r)\)

对于这组样例:

7
1 2 2 3 3 4 5

我们以能力值为横轴画出柱状图。

如果划分成 \(G_5^1\)\(G_3^2\),人最少的组有 2 人。

而分成 \(G_3^1\)\(G_5^2\),的情况更优。因为这样分人最少的组有 3 人。

于是我们可以知道,对于任意 \(G_j^i,G_l^k~(i\le k,j\ge l)\),重组为 \(G_k^i,G_l^j\) 一定不会更劣。即最优解中小组两两不包含,\(l\) 更小的组,\(r\) 也一定更小。(证明很容易,可以自己画个图感受一下,我就不写了哈)

于是我们用队列维护每组的人数,依次处理图中“每一列”。可知队列中每一组的 \(l\)\(r\) 都是单调不降的。

  1. 若这一列比队列长度大,则入队(添加新小组);
  2. 若这一列比队列长度低,则出队(旧的小组结束);

无论何种情况,最后全队列都要 \(+1\),用懒标记 shift 维护即可。

由于最多有 \(n\) 组,每个小组只进出队列一次,所以时间复杂度为 \(O(n)\),而排序 \(O(n \log n)\),是瓶颈。跑得飞快,卡卡常就到了 72ms,目前全谷最优解。

蒟蒻码

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#define int unsigned int  // 卡常
#define N 100000
#define INF 0x7f7f7f7f
using namespace std;
char buf[1<<21],*p=buf;
int a[N],q[N],hd,tl,len,cur,cnt,shift,ans=INF;
inline void read(int &x){
    int c;
    while((c=*p++)<'0'||c>'9');
    for(x=c^48;(c=*p++)>='0'&&c<='9';x=(x<<3)+(x<<1)+(c^48));
}
inline void work(int x){  // x为下一列的位置
    if(x-cur>1){  // 中间某列高度为 0,即数字不连续
        if(!len){  // 队列空,即上一次刚刚全部出队,出现“孤列” 
            putchar('1'),exit(0);
        }
        while(len){  // 全部出队,更新ans
            ans=min(ans,q[hd++]+shift);
            --len;
        }
    }
    else{
        if(cnt>len)  // 情况一
            for(int j=len;j<cnt;++j)
                q[tl++]=1-shift;  // 入队的数实际为1
        else if(cnt<len)  // 情况二
            for(int j=cnt;j<len;++j)
                ans=min(ans,q[hd++]+shift);
        len=cnt,++shift;  // 整体加一
    }
}
signed main(){
    int n;
    fread(buf,1,1<<21,stdin);
    read(n);
    if(n==1){
        putchar('1');
        return 0;
    }
    for(int i=0;i<n;++i) read(a[i]); 
	sort(a,a+n),cur=a[0],cnt=1;
	for(int i=1;i<n;++i)  // 统计每个数字出现次数,即每列高度
        if(a[i]==cur) ++cnt;
        else work(a[i]),cur=a[i],cnt=1;
    work(INF);  // 最后一列
    printf("%d",ans);
	return 0;
}

Update 2025.2.11:修正时间复杂度分析。
Update 2025.6.15:微调图片与文字间距。
Update 2025.6.16:调整公式上下标。

posted @ 2025-06-06 20:56  xiaoniu142857  阅读(29)  评论(0)    收藏  举报