组合计数 - Close Tuples (hard version) - CF 690 E2

组合计数 - Close Tuples (hard version) - CF 690 E2

题意:

给 定 一 个 长 度 为 n 的 序 列 a , 给定一个长度为n的序列a, na

要 从 中 挑 选 一 个 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取模。 m109+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 na1,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 1T21051n21051m1001kn1ain

所 有 测 试 样 例 的 n 的 总 和 不 超 过 2 ⋅ 1 0 5 所有测试样例的n的总和不超过2·10^5 n2105

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<...<imm

那 么 对 于 每 一 个 元 素 a i , 目 标 应 当 是 统 计 跟 它 差 不 超 过 k 的 所 有 数 的 个 数 , 然 后 从 中 任 选 m − 1 个 , 那么对于每一个元素a_i,目标应当是统计跟它差不超过k的所有数的个数,然后从中任选m-1个, aikm1

为 了 避 免 重 复 统 计 , 我 们 对 每 个 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的个数, aiajaiaiajkaj

因 此 , 我 们 先 将 序 列 排 序 , 然 后 对 每 个 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} aiaikposi Ciposim1

则 答 案 为 : 则答案为: :

∑ i = 1 n C i − p o s i m − 1 \sum_{i=1}^nC_{i-pos_i}^{m-1} i=1nCiposim1

时间复杂度: O ( n ⋅ l o g   n ) O(n·log\ n) O(nlog 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值