CF145C Lucky Subsequence 题解

首先,我们对这个幸运数进行分析,发现:

  • \(10^9\) 以内只有 \(1023\) 个幸运数,即 \(\sum\limits_{i=0}^92^i\) 个。

考虑对幸运数和非幸运数分类讨论。

  1. 幸运数部分:
    01 背包裸题,\(dp_{i,j}\) 表示前 \(i\) 个幸运数里选了 \(j\) 个,转移方程为 \(dp_{i,j}=dp_{i-1,j}+dp_{i-1,j-1}\times num_i\),可滚动数组。
  2. 非幸运数部分
    设选了 \(j\) 个幸运数,一共有 \(m\) 个非幸运数,则有 \(C_m^{k-i}\) 种可能性。

所以答案就是 \(\sum\limits_{i=0}^{\min(l,k)}dp_{l,i}\times C_m^{k-i}\),其中 \(l\) 为幸运数的种类数。

时间复杂度 \(O(l^2+n)\)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll p=1e9+7;
const int N=1e5+5,M=1025;
ll qpow(ll x,int y){
    ll re=1;
    while(y){
        if(y&1) re=re*x%p;
        x=x*x%p;
        y>>=1;
    }return re;
}int n,k,m,l;
ll jc[N],inv[N],dp[M],num[M],ans;
unordered_map<int,int>a;
void init(){
	jc[0]=inv[0]=1;
	for(ll i=1;i<=n;i++){
		jc[i]=jc[i-1]*i%p;
		inv[i]=qpow(jc[i],p-2);
	}
}ll C(int x,int y){
	if(x<y) return 0;
	return jc[x]*inv[y]%p*inv[x-y]%p;
}int check(int x){
	while(x){
		int y=x%10;
		if(y!=4&&y!=7)
			return 0;
		x/=10;
	}return 1;
}int main(){
	cin>>n>>k;
	init();
	for(int i=1;i<=n;i++){
		int x;
		cin>>x;
		if(check(x)){
			if(!a[x]) a[x]=++l;
			num[a[x]]++;
		}else m++;
	}dp[0]=1;
	for(int i=1;i<=l;i++)
		for(int j=min(i,k);j;j--)
			dp[j]=(dp[j]+dp[j-1]*num[i])%p;
	for(int i=0;i<=min(l,k);i++)
		ans=(ans+dp[i]*C(m,k-i))%p;
	cout<<ans;
    return 0;
}
posted @ 2024-03-16 10:26  长安一片月_22  阅读(2)  评论(0编辑  收藏  举报