[Atcoder2292] Division into Two

Posted lslzf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Atcoder2292] Division into Two相关的知识,希望对你有一定的参考价值。

题目大意

给定n个不同的整数,求将它们分成两个集合X,Y,并且X集合中任意两个数的差>=A,Y集合中任意两个数的差>=B的方案数。

样例输入

5 3 7
1
3
6
9
12

样例输出

5

解析

不妨设(A>B),那么考虑如何动态规划。设(f[i])表示第一个集合最后选择的数是i时的方案数。只用枚举第一个集合前一个选的数是哪一个即可转移。但 这么做是(O(n^2))的。考虑从能够转移的点的性质出发。

对于能够转移到i的j,必须要满足的条件有

  • (S_i-S_j >= A)
  • 对于([j+1,i-1])中的数,满足任意两个数(x,y)都有(S_y-S_x>=B)

可以发现满足条件的j是一段连续位置。因此采用前缀和优化即可。

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#define int long long
#define N 100002
using namespace std;
const int mod=1000000007;
int n,a,b,i,m[N],sum[N],f[N];
int read()
{
    char c=getchar();
    int w=0;
    while(c<'0'||c>'9') c=getchar();
    while(c<='9'&&c>='0'){
        w=w*10+c-'0';
        c=getchar();
    }
    return w;
}
signed main()
{
    n=read();a=read();b=read();
    if(a>b) swap(a,b);
    for(i=1;i<=n;i++) m[i]=read();
    sort(m+1,m+n+1);
    for(i=3;i<=n;i++){
        if(m[i]-m[i-2]<a){
            puts("0");
            return 0;
        }
    }
    int l=0,r=0,ans=0;
    sum[0]=f[0]=1;
    for(i=1;i<=n;i++){
        while(r<i-1&&m[i]-m[r+1]>=b) r++;
        if(l<=r) f[i]=(sum[r]-sum[l-1]+mod)%mod;
        sum[i]=(sum[i-1]+f[i])%mod;
        if(i>1&&m[i]-m[i-1]<a) l=i-1;
    }
    for(i=n;i>=0;i--){
        ans=(ans+f[i])%mod;
        if(i<n&&m[i+1]-m[i]<a) break;
    }
    printf("%lld
",ans);
    return 0;
}

以上是关于[Atcoder2292] Division into Two的主要内容,如果未能解决你的问题,请参考以下文章

AtCoder Regular Contest 114 F Permutation Division

Division and Recursion--find the nearest points in two dimension

解决PHP提示Warning: Division by zero in错误

AtCoder ABC 155F Perils in Parallel

AtCoder Regular Contest 072 E:Alice in linear land

AtCoder ABC 129F Takahashi's Basics in Education and Learning