题意:

有一个长度为$N$的递增序列$S_i$,要把它分成$X,Y$两组,使得$X$中元素两两之差不小于$A$且$Y$中元素两两之差不小于$B$,求方案数

首先考虑$O\left(n^2\right)$的做法:

为了方便,我们令$S_0=-\infty$

设$f_{M,i,j}(M\in\{X,Y\},1\leq i\leq n,0\leq j\lt i)$表示已划分好$S_{1\cdots i}$且$S_j$是最后一个不属于$M$的元素的方案数

已算好$f_{X,1\cdots i,j}$和$f_{Y,1\cdots i,j}$,如何转移?

①若$S_{i+1}-S_i\geq A$,$S_{i+1}$可被放入$X$中,则$f_{X,i+1,0\cdots i-1}=f_{X,i,0\cdots i-1}$

否则$S_i,S_{i+1}$不可一起被放入$X$中,$f_{X,i+1,0\cdots i-1}=0$

②显然$f_{Y,i+1,i}=\sum\limits_{j=0}^{i-1}[S_{i+1}-S_j\geq B]f_{X,i,j}$

对$f_Y$的处理相似

最后的答案就是$\sum\limits_{i=0}^{n-1}f_{X,n,i}+\sum\limits_{i=0}^{n-1}f_{Y,n,i}$

#include<stdio.h>
#define ll long long
#define mod 1000000007
int fx[2010][2010],fy[2010][2010];
ll a[2010];
int main(){
	int n,i,j;
	ll A,B;
	scanf("%d%lld%lld",&n,&A,&B);
	for(i=1;i<=n;i++)scanf("%lld",a+i);
	a[0]=-4223372036854775807ll;
	fx[1][0]=fy[1][0]=1;
	for(i=1;i<n;i++){
		if(a[i+1]-a[i]>=A){
			for(j=0;j<i;j++)fx[i+1][j]=fx[i][j];
		}
		if(a[i+1]-a[i]>=B){
			for(j=0;j<i;j++)fy[i+1][j]=fy[i][j];
		}
		for(j=0;j<i;j++){
			if(a[i+1]-a[j]>=B)fy[i+1][i]=(fy[i+1][i]+fx[i][j])%mod;
			if(a[i+1]-a[j]>=A)fx[i+1][i]=(fx[i+1][i]+fy[i][j])%mod;
		}
	}
	j=0;
	for(i=0;i<n;i++)j=((j+fx[n][i])%mod+fy[n][i])%mod;
	printf("%d",j);
}

考虑优化~

首先我们肯定不能开二维数组,考虑当前DP到$S_i$,只存$f_{M,j}$,并看一看当$i$变为$i+1$对答案的影响

因为$S$是递增的,所以满足$S_{i+1}-S_j\geq B$的$S_j$一定是一段前缀,所以我们可以用二分找到右端点并用线段树求区间和

其他转移就相当于线段树的单点更新

再用lazy tag实现清零即可

#include<stdio.h>
#define ll long long
#define mod 1000000007
int sumx[400010],sumy[400010],lazx[400010],lazy[400010],*laz,*sum,n;
ll a[100010];
void pushdown(int x){
	if(laz[x]){
		laz[x<<1]=laz[x<<1|1]=1;
		sum[x<<1]=sum[x<<1|1]=0;
		laz[x]=0;
	}
}
int query(int L,int R,int l,int r,int x){
	if(L<=l&&r<=R)return sum[x];
	pushdown(x);
	int mid=(l+r)>>1,ans=0;
	if(L<=mid)ans=(ans+query(L,R,l,mid,x<<1))%mod;
	if(mid<R)ans=(ans+query(L,R,mid+1,r,x<<1|1))%mod;
	return ans;
}
void modify(int pos,int v,int l,int r,int x){
	if(l==r){
		sum[x]=(sum[x]+v)%mod;
		return;
	}
	pushdown(x);
	int mid=(l+r)>>1;
	if(pos<=mid)
		modify(pos,v,l,mid,x<<1);
	else
		modify(pos,v,mid+1,r,x<<1|1);
	sum[x]=(sum[x<<1]+sum[x<<1|1])%mod;
}
int queryx(int L,int R){
	laz=lazx;
	sum=sumx;
	return query(L,R,0,n-1,1);
}
void modifyx(int pos,int v){
	laz=lazx;
	sum=sumx;
	modify(pos,v,0,n-1,1);
}
int queryy(int L,int R){
	laz=lazy;
	sum=sumy;
	return query(L,R,0,n-1,1);
}
void modifyy(int pos,int v){
	laz=lazy;
	sum=sumy;
	modify(pos,v,0,n-1,1);
}
int main(){
	int i,l,r,mid,x,t1,t2;
	ll A,B;
	scanf("%d%lld%lld",&n,&A,&B);
	for(i=1;i<=n;i++)scanf("%lld",a+i);
	a[0]=-4223372036854775807ll;
	modifyx(0,1);
	modifyy(0,1);
	for(i=1;i<n;i++){
		l=0;
		r=i-1;
		while(l<=r){
			mid=(l+r)>>1;
			if(a[i+1]-a[mid]>=B){
				x=mid;
				l=mid+1;
			}else
				r=mid-1;
		}
		t1=queryx(0,x);
		l=0;
		r=i-1;
		while(l<=r){
			mid=(l+r)>>1;
			if(a[i+1]-a[mid]>=A){
				x=mid;
				l=mid+1;
			}else
				r=mid-1;
		}
		t2=queryy(0,x);
		if(a[i+1]-a[i]<A){
			sumx[1]=0;
			lazx[1]=1;
		}
		if(a[i+1]-a[i]<B){
			sumy[1]=0;
			lazy[1]=1;
		}
		modifyy(i,t1);
		modifyx(i,t2);
	}
	printf("%d",(queryx(0,n-1)+queryy(0,n-1))%mod);
}

[AGC009C]Division into 2的更多相关文章

  1. AGC009C Division into Two

    题意 有\(n\)个严格升序的数,请你分成两个集合\(A\)和\(B\),其中一个集合任意两数之差不小于\(x\),另一集合任意两数之差不小于\(y\). 问方案数,集合可以为空. $n \le 10 ...

  2. 【AGC009C】Division into Two

    [AGC009C]Division into Two 题面 洛谷 题解 首先有一个比较显然的\(n^2\)算法: 设\(f_{i,j}\)表示\(A\)序列当前在第\(i\)个,\(B\)序列当前在第 ...

  3. python from __future__ import division

    1.在python2 中导入未来的支持的语言特征中division(精确除法),即from __future__ import division ,当我们在程序中没有导入该特征时,"/&qu ...

  4. [LeetCode] Evaluate Division 求除法表达式的值

    Equations are given in the format A / B = k, where A and B are variables represented as strings, and ...

  5. 关于分工的思考 (Thoughts on Division of Labor)

    Did you ever have the feeling that adding people doesn't help in software development? Did you ever ...

  6. POJ 3140 Contestants Division 树形DP

    Contestants Division   Description In the new ACM-ICPC Regional Contest, a special monitoring and su ...

  7. 暴力枚举 UVA 725 Division

    题目传送门 /* 暴力:对于每一个数都判断,是否数字全都使用过一遍 */ #include <cstdio> #include <iostream> #include < ...

  8. GDC2016【全境封锁(Tom Clancy's The Division)】对为何对应Eye Tracked System,以及各种优点的演讲报告

    GDC2016[全境封锁(Tom Clancy's The Division)]对为何对应Eye Tracked System,以及各种优点的演讲报告 原文 4Gamer編集部:松本隆一 http:/ ...

  9. Leetcode: Evaluate Division

    Equations are given in the format A / B = k, where A and B are variables represented as strings, and ...

随机推荐

  1. 微信小程序base64编码解码以及utf-8解码

    function base64_encode (str) { // 编码,配合encodeURIComponent使用 var c1, c2, c3; var base64EncodeChars = ...

  2. MySQL使用笔记(六)条件数据记录查询

    By francis_hao    Dec 17,2016 条件数据记录查询 mysql> select field1,field2-- from table_name where 条件; 其中 ...

  3. Ubuntu使用vim编辑器时出现上下左右键变成ABCD

    今天在配置安装php时,要打开配置文件做些修改,肯定是要使用到vim编辑器的,我按照之前的使用命令之类的,在用到上下左右键时居然出现了ABCD,这我就纳闷了,难道Ubuntu的vim编辑器和别的不一样 ...

  4. JavaScript 被忽视的细节

    语句/表达式 换个角度理解语句(statemaents)和表达式(expressions):表达式不会改变程序的运行状态,而语句会.还有一种叫做表达式语句,可以理解为表达式和语句的交集,如({a:1} ...

  5. 开发中常遇到的Python陷阱和注意点

    最近使用Python的过程中遇到了一些坑,例如用datetime.datetime.now()这个可变对象作为函数的默认参数,模块循环依赖等等. 在此记录一下,方便以后查询和补充. 避免可变对象作为默 ...

  6. eclipse读取含有extjs的项目文件时卡死

    打开项目的.project文件,将<buildCommand>                        <name>org.eclipse.wst.jsdt.core.j ...

  7. kdtree学习记录

    [转载请注明来自 Galaxies的博客:http://cnblogs.com/galaxies] 这篇文章当做一个记录啦qwq 参考:<K-D Tree在信息学竞赛中的应用>(n+e, ...

  8. 说出JAVA中一些常用的类,包,接口,请各举5个~~~

    类:1.java.lang.Object2.java.lang.String3.java.lang.System4.java.io.file5.java.io.FileInputStream6.jav ...

  9. Linux 查看文件和文件夹大小

    当磁盘大小超过标准时会有报警提示,这时如果掌握df和du命令是非常明智的选择. df可以查看一级文件夹大小.使用比例.档案系统及其挂入点,但对文件却无能为力.    du可以查看文件及文件夹的大小. ...

  10. Jackson对多态和多子类序列化的处理配置

    目录 Jackson 多态类型的处理 Jackson Jackson可以轻松的将Java对象转换成json对象和xml文档,同样也可以将json.xml转换成Java对象. 多态类型的处理 jacks ...