题意:

有一个长度为$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. rpm的使用:查询、安装、卸载、升级

    RPM 有五种操作模式,分别为:安装.卸载.升级.查询和验证. RPM 安装操作 命令: rpm -i 需要安装的包文件名 举例如下: rpm -i example.rpm 安装 example.rp ...

  2. Grep basic and practice

    定义:Grep (Globally search for the reqular expression and print out the line). 好处:Grep 在执行时不需要先调用编辑程序, ...

  3. 通俗解释IOC原理

    1. IoC理论的背景 我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑. 图1:软件系统中耦合的对象 如果我们打开机 ...

  4. Substrings(hdu 4455)

    题意: 给定一个序列ai,个数为n.再给出一系列w:对于每个w,求序列中,所有长度为w的连续子串中的权值和,子串权值为子串中不同数的个数. /* dp[i]表示长度为i的序列不同元素个数之和. 考虑从 ...

  5. 【UOJ131/NOI2015D2T2-品酒大会】sam求后缀树

    题目链接:http://uoj.ac/problem/131 题意:给出一个字符串,第i个字符对应的值为a[i], 对于i∈[0,n),求最长公共前缀大于等于i的字串对个数,并求这些字符串对开头对应值 ...

  6. loj6030 「雅礼集训 2017 Day1」矩阵

    传送门:https://loj.ac/problem/6030 [题解] 以下把白称为0,黑称为1. 发现只有全空才是无解,否则考虑构造. 每一列,只要有0的格子都需要被赋值1次,所以设有x列有含有0 ...

  7. [BZOJ1391]解题报告|网络流的又一类建图&Dinic的若干优化

    1391: [Ceoi2008]order 有N个工作,M种机器,每种机器你可以租或者买过来. 每个工作包括若干道工序,每道工序需要某种机器来完成,你可以通过购买或租用机器来完成. 现在给出这些参数, ...

  8. Chrome浏览器跨域插件

    Moesif Origin & CORS Changer 这个插件允许发送跨域请求,重写Request Origin 和 CORS headers. 解决Debug Javascript时候出 ...

  9. ubuntu 安装wxpython以及boa-constructor

    直接参考 官方的安装文档. 学习python 的时候就 用 wxPython . 那个时候用的是windows 的版本. 现在 用 ubuntu 下开发了.没有搭建好环境. 其实就一句话: sudo ...

  10. csrf_execmp

    参考;https://www.cnblogs.com/zhaof/p/6281482.html 全局: 中间件 django.middleware.csrf.CsrfViewMiddleware 局部 ...