【题意】:给出n个数,问从这n个数中选k个数一共有多少种方案,其中不能包括两个相同的lucky number(lucky number指数位仅包含4和7的数字),1<=k<=n<=100000.

【题解】:先把lucky number离散化,然后对lucky number进行dp。
               设dp[i][j]表示前 i 种lucky number选了 j 种的方案数。
                     dp[i][j] = dp[i-1][j] + dp[i-1][j-1] * c[i],其中c[i]表示第 i 种lucky number的个数。
               然后ans = ∑C(cnt, i) * dp[luckycnt][k-i], cnt 为非lucky number数目,luckycnt 为lucky number 种类数。
               注意,组合数需要用逆元处理。

【代码】:
 1 #include "iostream"
 2 #include "cstdio"
 3 #include "cstring"
 4 #include "algorithm"
 5 #include "vector"
 6 #include "queue"
 7 #include "cmath"
 8 #include "string"
 9 #include "cctype"
10 #include "map"
11 using namespace std;
12 #define pb push_back
13 #define lc(x) (x << 1)
14 #define rc(x) (x << 1 | 1)
15 #define lowbit(x) (x & (-x))
16 #define ll long long
17 #define maxn 100050
18 const ll MOD = 1000000007LL;
19 map<intint> mp;
20 int n, k;
21 int luckycnt, cnt;
22 ll dp[1500], c[1500], p[maxn];
23 
24 void init() {
25     memset(c, 0, sizeof(c));
26     luckycnt = cnt = 0;
27     mp.clear();
28 }
29 
30 bool check(int x) {
31     while(x) {
32         if(x % 10 != 4 && x % 10 != 7) return false;
33         x /= 10;
34     }
35     return true;
36 }
37 
38 void Gcd(ll a, ll b, ll &d, ll &x, ll &y) {
39     if (!b) {
40         d = a, x = 1, y = 0;
41         return;
42     }
43     Gcd(b, a % b, d, y, x);
44     y -= x * (a / b);
45 }
46 
47 ll inv(ll a, ll n) {
48     ll d, x, y;
49     Gcd(a, n, d, x, y);
50     if (d == 1) return (x % n + n) % n;
51     else return -1;
52 }
53 
54 ll C(ll n, ll m) {
55     if(m == 0) return 1;
56     if(m > n) return 0;
57     ll res = (p[n] * inv(p[m], MOD)) % MOD;
58     res = (res * inv(p[n-m], MOD)) % MOD;
59     return res;
60 }
61 
62 void solve() {
63     memset(dp, 0, sizeof(dp));
64     dp[0] = 1;
65     for(int i = 1; i <= luckycnt; i++)
66         for(int j = i; j; j--)
67             dp[j] = (dp[j] + dp[j-1] * c[i]) % MOD;
68     ll ans = 0;
69     for(int i = 0; i <= k && i <= cnt; i++) {
70         if(k - i > luckycnt) continue;
71         ans = (ans + C(cnt, i) * dp[k-i]) % MOD;
72     }
73     cout << ans << endl;
74 }
75 
76 int main() {
77     p[0] = 1;
78     for(int i = 1; i < maxn; i++) p[i] = (p[i-1] * i) % MOD;
79     while(cin >> n >> k) {
80         init();
81         for(int i = 0, val; i < n; i++) {
82             cin >> val;
83             if(check(val)) {
84                 if(mp.find(val) == mp.end()) mp[val] = ++luckycnt;
85                 c[mp[val]]++;
86             } else cnt++;
87         }
88         solve();
89     }
90     return 0;
91 }
92