组合计数 - Close Tuples (hard version) - CF 690 E2
题意:
给 定 一 个 长 度 为 n 的 序 列 a , 给定一个长度为n的序列a, 给定一个长度为n的序列a,
要 从 中 挑 选 一 个 m 元 组 ( a i 1 , a i 2 , a i 3 , . . . , a i m ) , i 1 < i 2 < . . . < i m , 满 足 要从中挑选一个m元组(a_{i_1},a_{i_2},a_{i_3},...,a_{i_m}),i_1<i_2<...<i_m,满足 要从中挑选一个m元组(ai1,ai2,ai3,...,aim),i1<i2<...<im,满足
m a x ( a i 1 , a i 2 , a i 3 , . . . , a i m ) − m i n ( a i 1 , a i 2 , a i 3 , . . . , a i m ) ≤ k max(a_{i_1},a_{i_2},a_{i_3},...,a_{i_m})-min(a_{i_1},a_{i_2},a_{i_3},...,a_{i_m})\le k max(ai1,ai2,ai3,...,aim)−min(ai1,ai2,ai3,...,aim)≤k
计 算 满 足 这 样 的 m 元 组 , 共 有 多 少 组 , 答 案 对 1 0 9 + 7 取 模 。 计算满足这样的m元组,共有多少组,答案对10^9+7取模。 计算满足这样的m元组,共有多少组,答案对109+7取模。
输入:
首 行 一 个 正 整 数 T , 表 示 测 试 数 据 数 量 , 首行一个正整数T,表示测试数据数量, 首行一个正整数T,表示测试数据数量,
接 着 一 行 三 个 正 整 数 , 依 次 为 n , m , k 接着一行三个正整数,依次为n,m,k 接着一行三个正整数,依次为n,m,k
最 后 一 行 为 n 个 正 整 数 a 1 , a 2 , . . . , a n 最后一行为n个正整数a_1,a_2,...,a_n 最后一行为n个正整数a1,a2,...,an
输出:
一 个 正 整 数 , 表 示 答 案 。 一个正整数,表示答案。 一个正整数,表示答案。
数据范围:
1 ≤ T ≤ 2 ⋅ 1 0 5 , 1 ≤ n ≤ 2 ⋅ 1 0 5 , 1 ≤ m ≤ 100 , 1 ≤ k ≤ n , 1 ≤ a i ≤ n 1≤T≤2⋅10^5 ,1≤n≤2⋅10^5, 1≤m≤100,1≤k≤n,1≤a_i≤n 1≤T≤2⋅105,1≤n≤2⋅105,1≤m≤100,1≤k≤n,1≤ai≤n
所 有 测 试 样 例 的 n 的 总 和 不 超 过 2 ⋅ 1 0 5 所有测试样例的n的总和不超过2·10^5 所有测试样例的n的总和不超过2⋅105
Example
input
4
4 3 2
1 2 4 3
4 2 1
1 1 1 1
1 1 1
1
10 4 3
5 6 1 3 2 9 8 1 2 4
output
2
6
1
20
分析:
计数思想和——《Prime Game - ICPC 2018 南京》相似
要理解: 条 件 : i 1 < i 2 < i 3 < . . . < i m 的 含 义 是 , m 元 组 不 重 复 。 条件:i_1<i_2<i_3<...<i_m的含义是,m元组不重复。 条件:i1<i2<i3<...<im的含义是,m元组不重复。
那 么 对 于 每 一 个 元 素 a i , 目 标 应 当 是 统 计 跟 它 差 不 超 过 k 的 所 有 数 的 个 数 , 然 后 从 中 任 选 m − 1 个 , 那么对于每一个元素a_i,目标应当是统计跟它差不超过k的所有数的个数,然后从中任选m-1个, 那么对于每一个元素ai,目标应当是统计跟它差不超过k的所有数的个数,然后从中任选m−1个,
为 了 避 免 重 复 统 计 , 我 们 对 每 个 a i , 统 计 满 足 a j ≤ a i , 且 a i − a j ≤ k , 的 a j 的 个 数 , 为了避免重复统计,我们对每个a_i,统计满足a_j\le a_i,且a_i-a_j\le k,的a_j的个数, 为了避免重复统计,我们对每个ai,统计满足aj≤ai,且ai−aj≤k,的aj的个数,
因 此 , 我 们 先 将 序 列 排 序 , 然 后 对 每 个 a i , 二 分 查 找 第 一 个 大 于 等 于 a i − k 的 元 素 的 位 置 p o s i , 它 对 答 案 的 贡 献 为 C i − p o s i m − 1 因此,我们先将序列排序,然后对每个a_i,二分查找第一个大于等于a_i-k的元素的位置pos_i,\\ \ \\它对答案的贡献为C_{i-pos_i}^{m-1} 因此,我们先将序列排序,然后对每个ai,二分查找第一个大于等于ai−k的元素的位置posi, 它对答案的贡献为Ci−posim−1
则 答 案 为 : 则答案为: 则答案为:
∑ i = 1 n C i − p o s i m − 1 \sum_{i=1}^nC_{i-pos_i}^{m-1} i=1∑nCi−posim−1
时间复杂度: O ( n ⋅ l o g n ) O(n·log\ n) O(n⋅log n)
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
const int mod = 1e9+7;
const int N = 200010;
#define ll long long
int n, T;
int a[N];
int m, k;
ll quick_pow(int a,int b)
{
ll res = 1;
while(b)
{
if(b&1) res=res*a%mod;
a=(ll)a*a%mod;
b>>=1;
}
return res;
}
ll C(int n, int m)
{
if(n<m) return 0;
ll up = 1, down = 1;
for(int i=n;i>n-m;i--) up=up*i%mod;
for(int i=1;i<=m;i++) down=down*i%mod;
down = quick_pow(down,mod-2);
return up*down%mod;
}
int main()
{
ios::sync_with_stdio(false);
cin>>T;
while(T--)
{
cin>>n>>m>>k;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
ll ans = 0;
for(int i=1;i<=n;i++)
{
int pos = lower_bound(a+1,a+i+1,a[i]-k) - a;
ans = (ans + C(i - pos, m - 1))%mod;
}
cout<<ans<<endl;
}
return 0;
}