AT_agc009_c
Division into Two
思路
一道 DP 好题。
我们假定
DP 状态不难想到:令
首先我们需要枚举一个
(由于 递增,所以满足条件的对会越来越多,所以满足此条件的 是从一开始的前缀)- 对于
中的每一个数都满足两两之差 。(由于区间 和 ,如果后者不合法则前者一定不合法,那么发现是一个 到开头的后缀)。
那有的同学就会想,为什么新加入
注意我们刚开始判断掉的情况,假设上次
可转移的便是二者的交集。二者都可以用双指针一类的方式维护,然后作前缀和即可快速求得,复杂度为
对于代码而言:
- 这道题对于后缀的处理还是很有讲究的。代码最后一个
if
语句:由于到下一轮循环才用到( 增加 ),所以等价于 的时候知道了 推出只能取到 (因为以 转移,那么 还是可以到的,因为 区间内只有一个数,一定满足要求) 。开头时无需判断的。 - 最有统计答案时,需要累加多个
f[i]
,遇到 则停止。原因是这样相当于后面的数都丢入 集合中,如果不统计答案是不全面的。而遇到前文的条件时, 还是可以累加的,理由和 1 中括号前半句话的道理是一样的。但是后面就不行了,其实总的说 1 点理解了这点其实更好理解些。 - 代码中使用了边做边统计的方式,可以考虑分开处理的代码。
对于第 2 点,我认为比较难理解,在此特意点出。
代码
#include<cstdio>
#include<algorithm>
using namespace std;
#define Ls(i,l,r) for(int i=l;i<r;++i)
#define Rs(i,l,r) for(int i=l;i>r;--i)
#define Le(i,l,r) for(int i=l;i<=r;++i)
#define Re(i,l,r) for(int i=l;i>=r;--i)
#define L(i,l) for(int i=0;i<l;++i)
#define E(i,l) for(int i=1;i<=l;++i)
#define W(t) while(t--)
const int N=100010,mod=1e9+7;
typedef long long ll;
int n;
ll a,b,s[N],sum[N];
int main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
// ios::sync_with_stdio(0);
// cin.tie(0);
// cout.tie(0);
#endif
// Insert Code Here
scanf("%d%lld%lld",&n,&a,&b);
if(a<b)swap(a,b);
E(i, n)scanf("%lld",s+i);
E(i, n-2)if(s[i+2]-s[i]<b)return puts("0"),0;
sum[0]=1;
int r=0,l=0;
E(i, n){
while(r<i&&s[i]-s[r+1]>=a)++r;
ll f=0;
if(l<=r)f=(sum[r]-(r?sum[l-1]:0)+mod)%mod;
sum[i]=(sum[i-1]+f)%mod;
if(i>1&&s[i]-s[i-1]<b)l=i-1;
}
ll ans=0;
Re(i, n, 0){
(ans+=(sum[i]-sum[i-1]+mod)%mod)%=mod;
if(i<n&&s[i+1]-s[i]<b)break;
}
printf("%lld",ans);
return 0;
}
本文作者:wscqwq
本文链接:https://www.cnblogs.com/wscqwq/p/17449295.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步