CF1793E题解

Problem - 1793E - Codeforces *2600

备注

2024.10.19 考试 T2。考场未能想出正解,找到性质但没有根据性质往 dp 方面想,而是想通过多枚举状态找最优解,需要反思!

简要题意

有一个数列 A,我们需要将其分成若干组。对于一个 i,若 i 所在的分组中元素个数大于等于 ai 则有贡献,给出 q 次询问,求分成 x 组时最大贡献。

数据范围:2n,q3×105,1ai,xn

题解

首先观察题目我们可以得出以下性质:

  1. 我们将 Aai 排序,选前面的一段满足条件肯定比后面的更优;(显然)
  2. 我们分组时将相邻的一段一起选一定不劣;

所以我们每次需要做的事其实就是选择一段前缀让它满足条件

我们先设 ansi 表示分成 i 组的最大贡献,但是想直接转移肯定不现实,经过尝试我们只能发现: ansi 具有单调性。

这时我们需要另外引入几个辅助函数,我们设 fi 表示钦定第 i 个数对答案有贡献时最多能分多少组,因为对于 i,我们需要将第 iai+1 到第 i 个数分成一组,所以转移方程为:fi=fiai+1,但是若 ai>ifi 就无意义,这里需要注意。若 fi 有意义,那么当前分的组数就为 fi+ni 组;否则组数为 nai+1

然后就能够求出 i 个有贡献时的答案,然后根据 ansi 单调性可以直接后缀取最大值,时间复杂度瓶颈在于排序,是 O(nlogn) 的,但是有人用桶排序 O(n) 更优。

代码

signed main(){
	freopen("xcpc.in", "r", stdin);
	freopen("xcpc.out", "w", stdout);
	n = rd(), q = rd();
	for(int i = 1; i <= n; ++i)a[i] = rd();
	sort(a + 1, a + 1 + n);
	for(int i = 1; i <= n; ++i){
		if(a[i] <= i)f[i] = f[i - a[i]] + 1, g = f[i] + n - i;
		else f[i] = 0, g = n - a[i] + 1;
		f[i] = max(f[i], f[i - 1]);
		ans[g] = i;
	}
	for(int i = n; i; --i)ans[i] = max(ans[i], ans[i + 1]);
	for(int i = 1; i <= q; ++i){
		int x = rd();
		printf("%d ", ans[x]);
	}
	return 0;
}
posted @   Lyrella  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示