题目传送门
首先可以发现这是一个dp计数题。
题目可以转化成
有一个数组: b 1 , b 2 , b 3 , b 4 . . b n b_1,b_2,b_3,b_4..b_n b1,b2,b3,b4..bn满足 b i > b i − 1 b_i>b_{i-1} bi>bi−1,你要给每一个数图上两种颜色: 0 / 1 0/1 0/1,设 c i c_i ci表示第i个球的颜色。你要使得 min { ∣ b i − b j ∣ } ≥ A , ( c i = c j = 0 ) \min\{|b_i-b_j|\}\geq A,(c_i=c_j=0) min{∣bi−bj∣}≥A,(ci=cj=0)且 min { ∣ b i − b j ∣ } ≥ B , ( c i = c j = 1 ) \min\{|b_i-b_j|\}\geq B,(c_i=c_j=1) min{∣bi−bj∣}≥B,(ci=cj=1)
我们考虑最后的涂色样子:肯定是一段0/1,一段1/0,一段0/1…最后也是一段0/1。
我们可以想到一种暴力的dp转移: d p i , j , k dp_{i,j,k} dpi,j,k表是考虑到第i个,上一个颜色为0的位置,上一个颜色为1的位置。
这样的做法是 O ( n 4 ) O(n^4) O(n4)的。
如果用线段树/BIT 优化可以做到 O ( n 3 ∗ l o g 2 ( n ) ) O(n^3*log_2(n)) O(n3∗log2(n))的。
显然过不去。
而且貌似空间也达到了 O ( n 3 ) O(n^3) O(n3)不可能更优了。
但是仔细考虑就会发现,我们只需要存储 j , k j,k j,k的信息,因为 i = max ( j , k ) i=\max(j,k) i=max(j,k)。
这样空间就可以变为 O ( n 2 ) O(n^2) O(n2)的了。
这让我想到了ABC 176的F题也有一个类似的思想。
这样的化时间复杂度是 O ( n 2 ∗ l o g 2 ( n ) ) O(n^2*log_2(n)) O(n2∗log2(n)),空间是 O ( n 2 ) O(n^2) O(n2)的。
都不行。
我们就需要另外想一个方法。
其实我们可以用 d p i , c o l dp_{i,col} dpi,col表示以i结尾的段的颜色是col。
转移也不难想:
d p i , c o l = ∑ d p i ′ , c o l ⊗ 1 dp_{i,col}=\sum dp_{i\prime,col \otimes1} dpi,col=∑dpi′,col⊗1
那么 i ′ i\prime i′有什么条件呢?
首先可以发现由于i是一个结尾,所以 s i + 1 − s i ′ ≥ A / B s_{i+1}-s_{i\prime}\geq A/B si+1−si′≥A/B。然后必须 s i ′ + 1 . . . s i s_{i\prime+1}...s_i si′+1...si每两个相邻的数之间 ≥ A / B \geq A/B ≥A/B。
后面的那个显然就可以预处理。前面的那个由于数组是单调的,所以可以two pointers来预处理。设其为 p i , c o l p_{i,col} pi,col。
假设 f a r i , c o l far_{i,col} fari,col表示第i个位置图col往前最远可以到达的合法位置(相邻的两个数之间的差 ≥ A / B \geq A/B ≥A/B )。
然后dp式子就可以改写:
d p i , c o l = ∑ i ′ = f a r i , c o l − 1 p i + 1 , c o l ⊗ 1 d p i , c o l ⊗ 1 dp_{i,col}=\sum_{i\prime=far_{i,col}-1}^{p_{i+1,col\otimes 1}} dp_{i,col\otimes1} dpi,col=i′=fari,col−1∑pi+1,col⊗1dpi,col⊗1
这个用BIT/线段树就ok了。
Code:
/*
{By GWj
*/
#pragma GCC optimize(2)
#include
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define R(a) cin>>a
#define R2(a,b) cin>>a>>b
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int N=100000;
const int MOD=1e9+7;
class BIT{
int bit[N+10]={0};
int sum(int i){
int s=0;
while(i>0){
s=(s+bit[i])%MOD;
i-=i&(-i);
}
return s;
}
public:
void add(int i,int x=1){
while(i<=N){
bit[i]=(bit[i]+x)%MOD;
i+=i&(-i);
}
}
public:
int query(int l,int r){
if(l>r) return 0;
return (sum(r)-sum(l-1)+MOD)%MOD;
}
}bit[2];
int n;
LL a,b,s[100000+1];
int far[N+1][2],f[2];
/*
f_{i,0}=\sum f_{i\prime,1},(i\prime < i\ and \ s_{i+1}-s_{i\prime}>=A/B)
*/
int main(){
fastio;
cin>>n>>a>>b;
rb(i,1,n)
R(s[i]);
rb(i,1,n){
far[i][0]=far[i][1]=i;
if(s[i]-s[i-1]>=a){
far[i][0]=far[i-1][0];
}
if(s[i]-s[i-1]>=b){
far[i][1]=far[i-1][1];
}
check_max(far[i][0],1);
check_max(far[i][1],1);
}
int p1=0,p0=0;
rb(i,1,n){
f[0]=f[1]=0;
if(i!=n){
while(s[i+1]-s[p0+1]>=a){
// cout<
p0++;
}
while(s[i+1]-s[p1+1]>=b){
// cout<
p1++;
}
}
else{
p0=p1=n;
}
int l,r;
l=far[i][0]-1;
r=p1;
check_max(l,1);
f[0]=bit[1].query(l,r);
if(far[i][0]==1){
f[0]++;
}
l=far[i][1]-1;
r=p0;
check_max(l,1);
f[1]=bit[0].query(l,r);
if(far[i][1]==1){
f[1]++;
}
rep(j,2){
bit[j].add(i,f[j]);
}
}
cout<<(f[1]+f[0])%MOD<<endl;
return 0;
}