
- 题意:给你一长度为(n)的序列(可能含有相等元素),你要找到(m)个位置不同的元素使得(max(a_{i-1},a_{i_2},...,a_{i_m})-min(a_{i-1},a_{i_2},...,a_{i_m})le k),问你共有多少种不同的元祖满足条件,对答案(mod 1e9+7).
- 题解:我们可以先用map做桶统计每个数出现的次数,然后枚举([1,n]),用前缀和(pre)统计出现的次数,然后我们再去枚举([1,n]),我们每次将(i)和([1,i-1])看成两部分,从(i)和([1,i-1])中选数,这样可以做到不重复不漏选,每次枚举从(i)中选的次数和([1,i-1])选的次数求组合数即可.
- 代码:
#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
#define rep(a,b,c) for(int a=b;a<=c;++a)
#define per(a,b,c) for(int a=b;a>=c;--a)
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
int t;
int n,m,k;
int a[N];
int f[N],inv[N];
int pre[N];
map<int,ll> mp;
int add(int x,int y){
x+=y;
if(x>=mod) x-=mod;
return x;
}
int mul(int x,int y){
return 1ll*x*y%mod;
}
int fpow(int a,int b){
int res=1;
while(b){
if(b&1) res=mul(res,a);
a=mul(a,a);
b>>=1;
}
return res;
}
int C(int n, int m){
if(n<m) return 0;
return mul(f[n],mul(inv[n-m],inv[m]));
}
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>t;
f[0]=1;
rep(i,1,N-1) f[i]=mul(f[i-1],i);
inv[N-1]=fpow(f[N-1],mod-2);
per(i,N-2,0) inv[i]=mul(inv[i+1],i+1);
while(t--){
cin>>n>>m>>k;
mp.clear();
rep(i,1,n){
cin>>a[i];
mp[a[i]]++;
}
if(m==1){
cout<<n<<'
';
continue;
}
rep(i,1,n){
pre[i]=pre[i-1]+mp[i];
}
ll ans=0;
rep(i,1,n){
int cur=mp[i];
if(!cur) continue;
int psum=pre[i-1]-((i-k-1>=0)?pre[i-k-1]:0);
rep(j,1,min(cur,m)) ans=add(ans,mul(C(cur,j),C(psum,m-j)));
}
rep(i,1,n) pre[i]=0;
cout<<ans<<'
';
}
return 0;
}