www 被大佬们吊打了|

wscqwq

园龄:2年粉丝:2关注:3

AT_agc009_c

Division into Two

思路

一道 DP 好题。

我们假定 ABA 对应 X 集合,B 对应 Y 集合)。我们先判掉存在 3 个数两两之差小于 B 的情况(根据鸽巢原理,三数二集合,这三者必定有二者分在一起)。

DP 状态不难想到:令 fi 表示前 i 个数都划分完成,其中第 i 个数是分在 X 的方案数。

首先我们需要枚举一个 j,那么 [j+1,i1] 这一段都放在 Y 集合中。然后我们分析得到合法的 j 需要满足的要求:

  • j<i
  • sisjA(由于 si 递增,所以满足条件的对会越来越多,所以满足此条件的 j 是从一开始的前缀
  • 对于 [j+1,i1] 中的每一个数都满足两两之差 B。(由于区间 [j,i1][j+1,i1],如果后者不合法则前者一定不合法,那么发现是一个 i1 到开头的后缀)。

那有的同学就会想,为什么新加入 Y 的一段就一定合法呢?也可能不合法呀!

注意我们刚开始判断掉的情况,假设上次 Y 集合中最后的数是 ak,由于 aj+1ak<B,又有 ak<aj<aj+1,那么这三者两两作差一定 <B(因为最大的和最小的之差已经 <B,那么相邻的就一定更小),所以已经被我们判掉了,不需要担心正确性。

可转移的便是二者的交集。二者都可以用双指针一类的方式维护,然后作前缀和即可快速求得,复杂度为 O(1)

对于代码而言:

  1. 这道题对于后缀的处理还是很有讲究的。代码最后一个 if 语句:由于到下一轮循环才用到(i 增加 1),所以等价于 i 的时候知道了 s[i1]s[i2]<b 推出只能取到 i2(因为以 i2 转移,那么 i1 还是可以到的,因为 [i1,i1] 区间内只有一个数,一定满足要求) 。开头时无需判断的。
  2. 最有统计答案时,需要累加多个 f[i],遇到 si+1si<B 则停止。原因是这样相当于后面的数都丢入 B 集合中,如果不统计答案是不全面的。而遇到前文的条件时,i 还是可以累加的,理由和 1 中括号前半句话的道理是一样的。但是后面就不行了,其实总的说 1 点理解了这点其实更好理解些。
  3. 代码中使用了边做边统计的方式,可以考虑分开处理的代码。

对于第 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 中国大陆许可协议进行许可。

posted @   wscqwq  阅读(11)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起