题解:洛谷 P11455([USACO24DEC] Cowdepenence G)

Link

1. Description

形式化题意来自 Deepseek。

给定序列 \(a_1, a_2, \dots, a_N\),对于每个 \(x \in [1, N]\),定义:

  • 友好小组:集合 \(S \subseteq \{1, 2, \dots, N\}\) 满足:
    • \(\forall i, j \in S, a_i = a_j\)
    • \(\forall i, j \in S, |i - j| \leq x\)
  • 划分:将 \(\{1, 2, \dots, N\}\) 划分为若干友好小组,且每个元素属于恰好一个小组。
  • 目标:求最小的划分大小(即最少小组数)。

要求对于每个 \(x\),输出对应的最小划分大小。

2. Solution

显然,我们可以分开考虑每个品种的奶牛,不妨依此将奶牛分成若干类,考虑两种不同的情况,种类数很少的情况和种类数很多的情况。

显然有贪心:假定现在这一组奶牛的左端点为 \(L\),而枚举的奶牛的下标为 \(i\),如果 \(i-L\le x\),那么就放在这一组中,否则另开一组。

我们假定现在要求一个特定种类奶牛在 \(x\) 为一个特定值时的答案,可以使用二分加快速度,具体的,如果当前组的左端点为 \(L\),那么找到第一个大于 \(L+x\) 的位置作为新的左端点即可。

首先考虑种类数很少的情况,当我们限定了一个 \(x\),一个种类最多被分成 \(\lceil \frac{n}{x} \rceil\) 类,所以可以暴力枚举所有 \(x\) 求解,然后累加到答案中,时间复杂度为 \(O(cnt\sum_{i=1}^n \lceil \frac{n}{x} \rceil\log n)\),其中 \(cnt\) 表示种类数,由于 \(\sum_{i=1}^n \lceil \frac{1}{x} \rceil=\ln n\),所以时间复杂度为 \(O(cnt\times n\ln n\log n)\)

然后考虑种类数很多的情况,种类数很多,也就是每一组的个数就很少,而每一种可能的答案一共也就只有 \(siz\) 种,那么就可以找出所有的转折点,然后差分即可,可以使用整体二分,时间复杂度挺迷的。

考虑一般情况,当这一种的奶牛数量大于 \(\sqrt n\) 的时候,使用种类数少的方法求解,否则使用种类数多的方法求求解。

3. Code

/*by qwer6*/
/*略去缺省源和快读快写*/
const int N=1e5+5,inf=0x3f3f3f3f;
int n,tot,B;
int a[N],tmp[N];
vector<int>pos[N];
int cal(vector<int> &pos,int x){
	if(!x)return inf;
	int L=-inf,res=0;
	while(1){
		auto it=upper_bound(pos.begin(),pos.end(),L+x);
		if(it==pos.end())return res;
		res++,L=*it;
	}
}
namespace Subtask1{
	int ans[N];
	void count(int idx){
		for(int i=1,x;i<=n;i++){
			x=cal(pos[idx],i);
			if(x==1){
				for(int j=i;j<=n;j++)ans[j]++;
				break;
			}else ans[i]+=x;
		}
	}
}
namespace Subtask2{
	int ans[N];
	void CDQ(int l,int r,int ql,int qr,int idx){
		if(ql>qr)return ;
		if(l==r){
			ans[l+1]-=qr-ql+1;
			return ;
		}
		int mid=l+r>>1;
		int cnt=cal(pos[idx],mid+1);
		if(qr<=cnt)CDQ(mid+1,r,ql,qr,idx);
		else if(ql>cnt)CDQ(l,mid,ql,qr,idx);
		else{
			CDQ(l,mid,cnt+1,qr,idx);
			CDQ(mid+1,r,ql,cnt,idx);
		}
	}
	void count(int idx,int siz=-1){
		if(siz==-1)siz=pos[idx].size();
		ans[0]+=siz;
		CDQ(0,n,1,siz,idx);
	}
}
void solve(){
    B=sqrt(n);
    for(int i=1,siz;i<=tot;i++){
        siz=pos[i].size();
        if(siz>B)Subtask1::count(i);
        else Subtask2::count(i,siz);
    }
    for(int i=1;i<=n;i++){
        Subtask2::ans[i]+=Subtask2::ans[i-1];
        write(Subtask1::ans[i]+Subtask2::ans[i]),Nxt;
    }
}
signed main(){
	read(n);
	for(int i=1;i<=n;i++)tmp[i]=read(a[i]);
	sort(tmp+1,tmp+n+1);
	tot=unique(tmp+1,tmp+n+1)-tmp-1;
	for(int i=1;i<=n;i++){
		a[i]=lower_bound(tmp+1,tmp+tot+1,a[i])-tmp;
		pos[a[i]].push_back(i);
	}
	solve();
}
posted @ 2025-05-04 21:29  陈牧九  阅读(16)  评论(0)    收藏  举报