Loading [MathJax]/jax/output/CommonHTML/fonts/TeX/fontdata.js

[Atcoder2292] Division into Two

题目大意

给定n个不同的整数,求将它们分成两个集合X,Y,并且X集合中任意两个数的差>=A,Y集合中任意两个数的差>=B的方案数。

样例输入

5 3 7
1
3
6
9
12

样例输出

5

解析

不妨设A>B,那么考虑如何动态规划。设f[i]表示第一个集合最后选择的数是i时的方案数。只用枚举第一个集合前一个选的数是哪一个即可转移。但 这么做是O(n^2)的。考虑从能够转移的点的性质出发。

对于能够转移到i的j,必须要满足的条件有

  • S_i-S_j >= A
  • 对于[j+1,i-1]中的数,满足任意两个数x,y都有S_y-S_x>=B

可以发现满足条件的j是一段连续位置。因此采用前缀和优化即可。

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#define int long long
#define N 100002
using namespace std;
const int mod=1000000007;
int n,a,b,i,m[N],sum[N],f[N];
int read()
{
	char c=getchar();
	int w=0;
	while(c<'0'||c>'9') c=getchar();
	while(c<='9'&&c>='0'){
		w=w*10+c-'0';
		c=getchar();
	}
	return w;
}
signed main()
{
	n=read();a=read();b=read();
	if(a>b) swap(a,b);
	for(i=1;i<=n;i++) m[i]=read();
	sort(m+1,m+n+1);
	for(i=3;i<=n;i++){
		if(m[i]-m[i-2]<a){
			puts("0");
			return 0;
		}
	}
	int l=0,r=0,ans=0;
	sum[0]=f[0]=1;
	for(i=1;i<=n;i++){
		while(r<i-1&&m[i]-m[r+1]>=b) r++;
		if(l<=r) f[i]=(sum[r]-sum[l-1]+mod)%mod;
		sum[i]=(sum[i-1]+f[i])%mod;
		if(i>1&&m[i]-m[i-1]<a) l=i-1;
	}
	for(i=n;i>=0;i--){
		ans=(ans+f[i])%mod;
		if(i<n&&m[i+1]-m[i]<a) break;
	}
	printf("%lld\n",ans);
	return 0;
}
posted @   CJlzf  阅读(154)  评论(1编辑  收藏  举报
编辑推荐:
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
阅读排行:
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 数据库服务器 SQL Server 版本升级公告
· 程序员常用高效实用工具推荐,办公效率提升利器!
· C#/.NET/.NET Core技术前沿周刊 | 第 23 期(2025年1.20-1.26)
点击右上角即可分享
微信分享提示