zoukankan      html  css  js  c++  java
  • CodeForces 146E Lucky Subsequence(组合数+DP)

    题目描述

    Petya loves lucky numbers very much. Everybody knows that lucky numbers are positive integers whose decimal record contains only the lucky digits 4 and 7. For example, numbers 47, 744, 4 are lucky and 5, 17, 467 are not.

    Petya has sequence aa consisting of nn integers.

    The subsequence of the sequence aa is such subsequence that can be obtained from aa by removing zero or more of its elements.

    Two sequences are considered different if index sets of numbers included in them are different. That is, the values ​of the elements ​do not matter in the comparison of subsequences. In particular, any sequence of length nn has exactly 2^{n}2n different subsequences (including an empty subsequence).

    A subsequence is considered lucky if it has a length exactly kk and does not contain two identical lucky numbers (unlucky numbers can be repeated any number of times).

    Help Petya find the number of different lucky subsequences of the sequence aa . As Petya's parents don't let him play with large numbers, you should print the result modulo prime number 1000000007100000000(10^{9}+7)(109+7) .

    输入输出格式

    输入格式:

     

    The first line contains two integers nn and k(1<=k<=n<=10^{5})(1<=k<=n<=105) . The next line contains nn integers a_{i}ai ( 1<=a_{i}<=10^{9}1<=ai<=109 ) — the sequence aa .

     

    输出格式:

     

    On the single line print the single number — the answer to the problem modulo prime number 1000000007100000000(10^{9}+7)(109+7) .

     

    输入输出样例

    输入样例#1: 
    3 2
    10 10 10
    
    输出样例#1: 
    3
    
    输入样例#2: 
    4 2
    4 4 7 7
    
    输出样例#2: 
    4
    

    说明

    In the first sample all 3 subsequences of the needed length are considered lucky.

    In the second sample there are 4 lucky subsequences. For them the sets of indexes equal (the indexation starts from 1 ): {1,3}1,3 , {1,4}1,4 , {2,3}2,3 and {2,4}2,4 .

    题意:

    定义神仙数为只含4和7的数字

    给出n个数字,让你从里面取k个,同一个神仙数不能重复取,求取法数

    题解

    首先如果没有重复取这个限制,这就是一道线性求组合数。

    就算有这个限制,全部不能重复取也是可做的,所以自然会感觉这种部分可重复部分不能的题很难受,于是会想到将原来的数组拆成两组,一组只有神仙数,一组只有非神仙数

    然后答案就是在神仙数中取i个,在非神仙数中取k-i个的方案相乘,再将i=1~n的所有方案相加起来,就是答案

    非神仙数显然可以线性处理组合数,O(1)查询

    如今的问题是如何解决神仙数

    首先需要搞清楚神仙数的一个性质:他非常少

    这是可以证明的

    一位的时候有4/7两种,两位有4种,反正1e9内大概不到3000个

    这可以n^2DP

    令dp[i][j]表示到第i位取j个数的方案数

    显然dp[i][j]=dp[i-1][j]+dp[i-1][j-1]*num[a[i]]

    num[a[i]]表示大小为a[i]的神仙数个数

    于是就可以A掉这题了

    代码如下:

    #include<map>
    #include<cmath>
    #include<stack>
    #include<cstdio>
    #include<string>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define mod 1000000007
    using namespace std;
    
    long long fac[100010],inv[100010],n,m,ans;
    map<long long,int> m1;
    vector<long long> a,b;
    long long dp[3010][3010];
    
    long long kasumi(long long a,long long b)
    {
        long long ans=1;
        while(b)
        {
            if(b&1)
            {
                ans=ans*a%mod;
            }
            a=a*a%mod;
            b>>=1;
        }
        return ans;
    }
    
    long long c(int n,int m)
    {
        if(n>m) return 0ll;
        return fac[m]*inv[n]%mod*inv[m-n]%mod;
    }
    
    int check(long long x)
    {
        while(x)
        {
            if(x%10!=4&&x%10!=7) return 0;
            x/=10;
        }
        return 1;
    }
    
    int main()
    {
        fac[0]=1;
        inv[0]=1;
        for(int i=1; i<=100000; i++)
        {
            fac[i]=fac[i-1]*i%mod;
        }
        inv[100000]=kasumi(fac[100000],mod-2);
        for(int i=99999; i>=1; i--)
        {
            inv[i]=inv[i+1]*(i+1)%mod;
        }
        scanf("%lld%lld",&n,&m);
        long long tmp;
        for(int i=1; i<=n; i++)
        {
            scanf("%lld",&tmp);
            if(check(tmp))
            {
                if(m1.count(tmp))
                {
                    m1[tmp]++;
                }
                else
                {
                    m1[tmp]++;
                    a.push_back(tmp);
                }
            }
            else
            {
                b.push_back(tmp);
            }
        }
        for(int i=0;i<=3000;i++)
        {
            dp[i][0]=1;
        }
        if(a.size()>=1)
        {
            dp[0][1]=m1[a[0]];
            for(int i=1; i<a.size(); i++)
            {
                for(int j=1; j<=a.size(); j++)
                {
                    dp[i][j]=dp[i-1][j]+dp[i-1][j-1]*m1[a[i]];
                    dp[i][j]%=mod;
                }
            }
        }
        int lena=a.size(),lenb=b.size();
        ans+=c(m,lenb);
        for(int i=1; i<=min(lena*1ll,m); i++)
        {
            ans+=dp[lena-1][i]*c(m-i,lenb);
            ans%=mod;
        }
        printf("%lld
    ",ans);
    }
  • 相关阅读:
    什么时候加上android.intent.category.DEFAULT和LAUNCHER
    android中跨进程通讯的4种方式
    Unix Sockets in Go
    android Service 跨进程通信
    Android Activity和Intent机制学习笔记
    AIR 移动设备上的存储控制
    AIR Android开发APK结构详解
    android 内存管理
    Android权限大全
    运营商登录付费接入ANE打包心得
  • 原文地址:https://www.cnblogs.com/stxy-ferryman/p/9374205.html
Copyright © 2011-2022 走看看