题意:

有一个长度为$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. HDU 5655 四边形判断

    CA Loves Stick Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) ...

  2. POJ 3104 Drying(二分

    Drying Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 22163   Accepted: 5611 Descripti ...

  3. OSI 七层模型和 TCP/IP 四层模型 及 相关网络协议

    简介 OSI 是理论上的模型,也就是一个统一的国际标准,现在的很多网络设备或者是网络协议都不同程度的精简了自己的所谓的模型,那么他们为了自己的通讯兼容都会参考这个OSI模型 TCP/IP 包括: TC ...

  4. js密码的匹配正则

    匹配的密码是 数字大写或者小写的字母.符号. if(pwd.match(/[\d]/) && pwd.match(/[A-Za-z]/) && pwd.match(/[ ...

  5. C# 序列化原因 (转)

         1.什么是序列化 序列化是将对象状态转换为可保持或传输的格式的过程,在序列化过程中,对象的公共字段和私有字段以及类的名称(包括包含该类的程序集)都被转换为字节流,然后写入数据流.与序列化相对 ...

  6. 查看jar包源码

    1.Maven项目 如下图设置后,它会自动下载源文件,这样就能看到了 2.传统Java项目 2.1.安装 Jad 下载 Jad :http://varaneckas.com/jad/ 解压到任意目录即 ...

  7. mysql5.7.11安装遇到的问题

    首次安装mysql5.7.11绿色版,真是破费功夫,现记录安装中遇到的问题,只是解决了问题,而不清楚问题的由来. 问题一: 问题二: 问题三: 问题四: 我的my.ini配置文件: [mysql] # ...

  8. bzoj 5028: 小Z的加油店——带修改的区间gcd

    Description 小Z经营一家加油店.小Z加油的方式非常奇怪.他有一排瓶子,每个瓶子有一个容量vi.每次别人来加油,他会让 别人选连续一段的瓶子.他可以用这些瓶子装汽油,但他只有三种操作: 1. ...

  9. 端到端测试,protractor测试的教程

    之前我们介绍了如何测试某段js代码的逻辑是否正确,考虑的情况是否全面,但是在ui界面上我们每次做好的功能都要自己去填写内容,点击按钮等,那么是否存在自动化测试的工具呢,让这些事情可以自动完成,答案是肯 ...

  10. 如何重新签名ipa文件

    http://www.cocoachina.com/bbs/read.php?tid=185963 求ipa文件修改后重新打包的方法,我已经有开发者账号了. 替换了ipa里的图片后,就无法安装了,似乎 ...