给定 n n n个不同的整数 a 1 , a 2 , a 3 , . . . , a n a_1,a_2,a_3,...,a_n a1,a2,a3,...,an,求将它们分成两个集合 X , Y X,Y X,Y,并且 X X X集合中任意两个数的差 ≥ A \ge A ≥A, Y Y Y集合中任意两个数的差 ≥ B \ge B ≥B的方案数。
第一行三个正整数 n , A , B n,A,B n,A,B。
以下 n n n行, 每行一个正整数 a i a_i ai。
一行一个非负整数, 表示方案数 m o d 1000000007 mod\ 1000000007 mod 1000000007
5 3 7
1
3
6
9
12
5
7 5 3
0
2
4
7
8
11
15
4
8 2 9
3
4
5
13
15
22
26
32
13
还是挺好想的。
在这里为了方便设 A ≤ B A\le B A≤B, 同时将 a i a_i ai从小到大排序。
首先如果存在 i ∈ [ 3 , n ] i\in [3,n] i∈[3,n]满足 a i − a i − 2 < A a_i-a_{i-2}<A ai−ai−2<A, 就一定无解。
设 d p [ i ] dp[i] dp[i]表示一定取 a i a_i ai到 B B B集合的方案数, 那么对于 d p [ i ] dp[i] dp[i]转移区间一定是一段连续的区间 [ l , r ] [l,r] [l,r], 满足 ∀ i ∈ [ l + 2 , i − 1 ] , a i − a i − 1 ≥ A \forall i\in[l+2,i-1], a_i-a_{i-1}\ge A ∀i∈[l+2,i−1],ai−ai−1≥A且 a i − a r ≥ B a_i-a_{r}\ge B ai−ar≥B。因为我们保证了 A ≤ B A\le B A≤B, 所以不需要关心 a i − a r ≥ A a_i-a_r\ge A ai−ar≥A的问题。
这样预处理出来每个位置能向左连续多少个满足两两位置差 ≥ A \ge A ≥A, 就可以 O ( N ) O(N) O(N)DP了。
代码如下:
#include
#include
#include
#include
#include
#include
#include
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MOD 1000000007
#define MX 100500
#define ll long long
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
template <class T> IN T max(T a, T b) {return a > b ? a : b;}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
int n;
ll A, B, dat[MX];
int dp[MX], sum[MX], lef[MX];
IN int get(R int l, R int r)
{
if (l > r) return 0;
if (l <= 0) return sum[r];
return (sum[r] - sum[l - 1] + MOD) % MOD;
}
int main(void)
{
in(n), in(A), in(B);
if (A > B) std::swap(A, B);
for (R int i = 1; i <= n; ++i) in(dat[i]);
std::sort(dat + 1, dat + 1 + n);
dat[0] = -1e18;
for (R int i = 3; i <= n; ++i) if (dat[i] - dat[i - 2] < A) return puts("0"), 0;
for (R int i = 1; i <= n; ++i)
{
if (dat[i] - dat[i - 1] >= A) lef[i] = lef[i - 1];
else lef[i] = i;
}
dp[0] = sum[0] = 1;
int cur = 0, ans = 0;
for (R int i = 1; i <= n; ++i)
{
W (dat[i] - dat[cur + 1] >= B) ++cur;
dp[i] = get(lef[i - 1] - 1, cur);
sum[i] = (sum[i - 1] + dp[i]) % MOD;
}
for (R int i = n; ~i; --i)
{
(ans += dp[i]) %= MOD;
if (i != n && dat[i + 1] - dat[i] < A) break;
}
printf("%d", ans);
}