一道题

Description

仅包含4或7的数被称为幸运数。
一个序列的子序列被定义为从序列中删去若干个数,剩下的数组成的新序列。
两个子序列被定义为不同的当且仅当其中的元素在原始序列中的下标的集合不
相等。对于一个长度为N的序列,共有2^N个不同的子序列。(包含一个空序列)。
一个子序列被称为不幸运的,当且仅当其中不包含两个相同的幸运数。
对于一个给定序列,求其中长度恰好为K的不幸运子序列的个数,答案mod 10^9+7 输出。

Solution

此题堪称大型翻车现场, 有好几个人读错题. 一个人丢了20分.

只有我出了好几种错误.(数据太水了还能让我拿到分)

发现一共有\(2^1 + 2^2 + 2 ^ 3+\cdots\)种幸运数字, 也就是说\(10^9\)以内的数只有\(1023\)种幸运数字.(坑死一个叫zzx的人)
将给定的\(n\)个数分成幸运数和非幸运数, 统计出每种幸运数字出现的次数.

\(f(i,j)\)表示前\(i\)种幸运数字选出\(j\)个作为子序列的方案数.

转移方程

\[f(i,j)=f(i-1,j)+f(i-1,j-1)\cdot S_i \]

最后将非幸运数字加进去.
答案就是
\(\sum_{i=0}^kf(m, i){n\choose m - i}\)

Code

#include <map>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100005;
const int mod = 1e9 + 7;
inline long long Pow(int a, int b) {
    long long res = 1, base = a;
    while (b) {
        if (b & 1) 
            res = res * base % mod;
        base = base * base % mod;
        b >>= 1;
    }
    return res;
}
inline long long Inv(int a) {
    return Pow(a, mod - 2);
}
long long fff[N];
inline long long F(int n) {
    if (fff[n]) return fff[n];
    fff[0] = 1;
    for (int i = 1; i <= 100000; i += 1)
        fff[i] = fff[i - 1] * i % mod;
    return fff[n];
}
inline long long C(int n, int m) {
    return (F(n) * Inv(F(m)) % mod) * Inv(F(n -m)) % mod;
}
inline bool Judge(int p) {
    while (p) {
        if (p % 10 != 4 and p % 10 != 7) return false;
        p /= 10;
    }
    return true;
}

int tot = 0;
int S[N];
long long f[2][N];
map<int, int> M;
int main () {
    freopen("lucky.in", "r", stdin);
    freopen("lucky.out", "w", stdout);
    int n, k;
    scanf("%d%d", &n, &k);
    int size = 0, tot = 0;
    for (int i = 0, temp; i < n; i += 1) {
        scanf("%d", &temp);
        if (Judge(temp)) {
            if (not M[temp]) M[temp] = ++tot;
            S[M[temp]] += 1;
        } else size += 1;
    }
    if (size + tot < k) {
        printf("%d\n", 0);
        return 0;
    }
    f[0][0] = 1;
    long long *F = f[1], *G = f[0];
    for (int i = 1; i <= tot; i += 1) {
        for (int j = 0; j <= tot; j += 1) {
            F[j] = ((j ? (G[j - 1] * S[i]) % mod : 0) + G[j]) % mod;
            F[j] %= mod;
            if (not F[j]) break;
        }
        swap(F, G);
    }
    long long res = 0;
    for (int i = 0; i <= k; i += 1) {
        if (k - i <= size) 
            res = (res + (G[i] * C(size, k - i) % mod)) % mod;
    }
    printf("%d\n", res);
    return 0;
}
posted @ 2018-11-01 14:30  Grary  阅读(227)  评论(0编辑  收藏  举报
博客园 首页 私信博主 编辑 关注 管理 新世界