(hgs 风格小清新题解)
简单 DP 题。咋这种题都 2400 啊。。。
注意到最终 (A) 和 (B) 都各一定能表示成 (s)(有序)的若干个区间。
于是对这个区间 DP。
我们考虑 (dp_{i,0/1}) 为考虑划分前 (i) 个,第 (i) 个分到 (A/B) 的方案数。
然后转移的话,就 (0) 转移到 (1) (1) 转移到 (0),决策要满足两个限制:
- 当前区间内部满足条件;
- 区间两端要满足条件。
然后随便推。发现 1 的决策集合是个 ([1,i]) 的后缀,即有下界;2 是个前缀,即有上界。
综合起来就是一个区间?前缀和随便维护一下。
1 可以用分段 for
预处理,2 傻逼写 lower_bound
,不傻逼发现单调性,two-pointers 随便维护。
然后做完了?
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1000000007,inf=0x3f3f3f3f3f3f3f3f;
const int N=100000;
int n,a,b;
int s[N+1];
int Sum[N+1][2];
int dp[N+1][2];
int lft[N+1][2];
int sum(int l,int r,bool tp){
if(l>r)return 0;
return (Sum[r][tp]-Sum[l-1][tp])%mod;
}
signed main(){
cin>>n>>a>>b;
for(int i=1;i<=n;i++)scanf("%lld",s+i);
for(int i=1,ie;i<=n;i=ie+1){
ie=i;while(ie+1<=n&&s[ie+1]-s[ie]>=a)ie++;
for(int j=i;j<=ie;j++)lft[j][0]=i;
}
for(int i=1,ie;i<=n;i=ie+1){
ie=i;while(ie+1<=n&&s[ie+1]-s[ie]>=b)ie++;
for(int j=i;j<=ie;j++)lft[j][1]=i;
}
dp[0][0]=dp[0][1]=Sum[0][0]=Sum[0][1]=1;
int las0=0,las1=0;
s[0]=-inf,s[n+1]=inf;
for(int i=1;i<=n;i++){
while(las0+1<i&&s[las0+1]<=s[i+1]-a)las0++;
while(las1+1<i&&s[las1+1]<=s[i+1]-b)las1++;
dp[i][0]=sum(lft[i][0]-1,las1,1);
dp[i][1]=sum(lft[i][1]-1,las0,0);
Sum[i][0]=(Sum[i-1][0]+dp[i][0])%mod;
Sum[i][1]=(Sum[i-1][1]+dp[i][1])%mod;
}
cout<<(dp[n][0]+dp[n][1]+10*mod)%mod;
return 0;
}