题意:

有一个长度为$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. [poj 3281]最大流+建图很巧妙

    题目链接:http://poj.org/problem?id=3281 看了kuangbin大佬的思路,还用着kuangbin板子orz   http://www.cnblogs.com/kuangb ...

  2. [poj 3436]最大流+输出结果每条边流量

    题目链接:http://poj.org/problem?id=3436 大力套kuangbin板过了orz #include<cstdio> #include<cstring> ...

  3. SpringMVC学习 -- @RequestParam , @RequestHeader , @CookieValue 的使用

    使用 @RequestParam 绑定请求参数值: value:参数名 , 仅有一个 value 属性时 , value 可以省略不写. required:是否必须.默认为 true , 表示请求参数 ...

  4. 【bzoj3196-二逼平衡树】线段树套平衡树

    http://acm.hust.edu.cn/vjudge/problem/42297 [题目描述] 写一种数据结构,来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间 ...

  5. bzoj2683/4066 简单题

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2683 http://www.lydsy.com/JudgeOnline/problem.ph ...

  6. COGS2090 Asm.Def找燃料

    时间限制:1 s   内存限制:256 MB [题目描述] “听说咱们要完了?”比利·海灵顿拨弄着操纵杆,头也不回地问Asm.Def. “不要听得风就是雨.” “开个玩笑嘛.不就是打机器人,紧张啥,你 ...

  7. 【洛谷 UVA11417】 GCD(欧拉函数)

    我们枚举所有gcd \(k\),求所有\(gcd=k\)的数对,记作\(f(k)\),那么\(ans=\sum_{i=1}^{n}(f(i)-1)*i\).为什么减1呢,观察题目,发现\(j=i+1\ ...

  8. 【mysql优化】大数据量分页优化

    limit 翻页原理 limit offset,N, 当offset非常大时, 效率极低, 原因是mysql并不是跳过offset行,然后单取N行, 而是取offset+N行,返回放弃前offset行 ...

  9. 编写类du命令Python脚本

    #!/usr/bin/env python #_*_ coding:utf-8 _*_ #计算整个目录的大小,脚本接受-H参数,来加上适当的单位 #功能像du看齐 import os,sys from ...

  10. C#区分大小写

    连属性也是要区分大小写的,如 获取数据长度 错误:strs.length 这样是报错的 正确:strs.Length