题目大意: 给定一个长度为 nn 的非负整数数组 aa,保证 aa 中元素至少有 n1n−1 个数字互不相同。 求 aa 的长度为 kk 的不同子序列的方案数,输出答案取模1e9+71e9+7的结果。

解题思路:关注什么时候的子序列会重复,会发现在下图中,影响的子序列是不包含下标3355的数且选择了一个重复的数
alt

推广::设重复的数的下标为 pos1,pos2(pos1<pos2)pos1,pos2(pos1<pos2),总方案数易知为CnkC^k_n,重复的方案为选择一个重复的数,且不再选择pos1pos1pos2pos2范围的数(pos1pos2)(意为在pos1与pos2之间只选一个数),方案数为Cn(pos2pos1+1)k1C^{k-1}_{n-(pos2-pos1+1)},所以答案为CnkCn(pos2pos1+1)k1C^k_n-C^{k-1}_{n-(pos2-pos1+1)}

TipTip:组合数CnmC^m_n中当m>nm>n时,结果为00

参考代码:

#define LL long long
using namespace std;
const int M=1e5+7;
const LL Mod=1e9+7;
int T,n,k,x;
int a[M];
map<int,int> mp;
LL P[M],ipow[M];

LL C(int m,int n){
	if(m==0) return 1;
    if(n<m) return 0; //注意!!!
	return ((P[n]*ipow[m])%Mod*ipow[n-m])%Mod;
}


LL qpow(LL x,LL tim){
	LL ret=1,tmp=x;
	while(tim){
		if(tim&1){
			ret=ret*tmp%Mod;
		} 
		tmp=tmp*tmp%Mod;
		tim>>=1;
	}
	return ret;
}
int main(){
	ios::sync_with_stdio(false);
	cin>>T;
	P[0]=1;
	for(int i=1;i<=1e5+5;i++){
		P[i]=P[i-1]*i%Mod;
		//cout<<P[i]<<"\n";
	}
	ipow[0]=1;
	ipow[1]=1;
	for(int i=2;i<=1e5+5;i++){
		ipow[i]=qpow(P[i],Mod-2);
		//cout<<ipow[i]<<"\n";
	}
	while(T--){
		int pos1=0,pos2=0,f=0;
		cin>>n>>k;
		for(int i=1;i<=n;i++){
			cin>>a[i]; mp[a[i]]++;
			if(mp[a[i]]==2) {
				f=1;x=a[i];
			}
		}
		mp.clear();
		if(f==1){
			for(int i=1;i<=n;i++){
			    if(a[i]==x){
				     if(pos1) pos2=i;
				     else pos1=i;
			    }
		    }
		}
		if(f){
			cout<<(C(k,n)-C(k-1,n-pos2+pos1-1)+Mod)%Mod<<"\n";
		}
		else cout<<C(k,n)<<"\n";
	}
}