Codeforces Round #104 (Div. 1) C Lucky Subsequence

题目链接:Lucky Subsequence

题意:只含有数字4和7的为幸运数字,对于一个长为 n 的序列,问有多少个长度为 k 的子序列(可以不用连续)中不包含两个相同的幸运数字,非幸运数字可以出现任意多次。

题解:因为序列中的数字小于等于 10^9 ,所以最多会有 2^10=1024 个不同的幸运数字,记录每一个幸运数字的个数。然后用 dp[i][j] 表示前 i 个幸运数字中共取 j 个的方法数,状态转移方程为 dp[i][j]=dp[i-1][j]+dp[i-1][j-1]×num[i],其中 num[i] 为第 i 个幸运数字出现的次数。最后的答案即为 Σdp[tot][j]×C(sum, k-j),sum为非幸运数字个数。

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const LL mod=1e9+7;

LL n,k,cnt,tot;
LL a[100005],b[100005],num[100005],fac[100005],dp[100005];

LL pow_mod(LL a,LL n){
    LL res=1,t=a;
    while(n){
        if(n&1) res=(res*t)%mod;
        t=(t*t)%mod;
        n/=2;
    }
    return res;
}
LL inv(LL x){
    return pow_mod(x,mod-2);
}
bool lucky(LL x){
    while(x){
        if(x%10!=4&&x%10!=7)
            return false;
        x/=10;
    }
    return true;
}
LL C(LL x,LL y){
    if(y==0) return 1;
    if(x<y) return 0;
    LL res=(fac[x]*inv(fac[y]))%mod;
    res=(res*inv(fac[x-y]))%mod;
    return res;
}

int main(){
    fac[0]=1;
    for(LL i=1;i<=100000;i++) fac[i]=(fac[i-1]*i)%mod;
    scanf("%lld%lld",&n,&k);
    for(LL i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        if(lucky(a[i])) b[++cnt]=a[i];
    }
    sort(b+1,b+1+cnt);
    LL sum=0;
    dp[0]=1;
    for(LL i=1;i<=cnt;i++){
        sum++;
        if(b[i]!=b[i+1]||i==cnt){
            tot++;
            for(LL j=tot;j>=1;j--){
                dp[j]=(dp[j]+dp[j-1]*sum%mod)%mod;
            }
            sum=0;
        }
    }
    LL ans=0;
    for(LL i=0;i<=k;i++){
        LL temp=dp[i]*C(n-cnt,k-i)%mod;
        ans=(ans+temp)%mod;
    }
    printf("%lld\n",ans);

    return 0;
}

 

posted on 2019-01-13 19:12  Psong  阅读(175)  评论(0编辑  收藏  举报

导航