传送门:https://ac.nowcoder.com/acm/contest/283/B
题目描述
假设有一条数列
。可以在里面抽出指定的项组成新的子数列
。
注意:子数列的次序必须和主数列的次序一样。
例如:
,只抽出双数项,就会有子数列。
。
引用自 子序列——维基百科
在中国文化里,4和“死”谐音,7和“气”谐音,都是不吉利的含义。现在我们定义所有只由4和7组成的数字为不吉利的数字,例如4、47、74、44、7774等。
现在有一个数列array, 元素个数为 n ,给定一个数 m ,你可以在array任意选取 m 个数字的子序列,对于任何一个子序列只要有任意位置下标不同则视为不同的子序列。
例如选择下标为
与下标为
的元素作为子序列,则是不同的子序列,不论元素集合是否相同。
现在要求选取的数字中同一个不吉利的数最多出现一次,请问有多少种选法?
答案可能很大,请输出答案对
取模之后的结果。
输入描述:
第一行为两个整数:n和m
接下来一行为 n 个整数,其中第i个表示array[i]
所有数据满足:
输出描述:
在一行内输出一个整数表示答案
题意概括:如题
解题思路:
记原数列 长度为 N
记录 每种不吉利数的个数,如果该类不吉利数只有一个那就保留在原数列中,否则把其余的都从原序列去掉。
记去掉重复不吉利数的序列长为 Slen
那么 剩下的序列里选 M 个 C( Slen, M) 这些是满足条件的子序列,但不是全部;
因为下标不同,子序列也不同。
所以我们刚才记录每种不吉利数 的个数就用上了,有多少种不吉利数就有多少个格子,而这些格子里的那个不吉利数可以替换成同种类型但是不同下标的。
举个栗子:
6 3
2 4 4 7 7 747
不吉利数 4 : 2个
不吉利数 7:2个
不吉利数 747 :1个
那么在 4 这个格子 我们有 2 种方案,在 7 这个格子有 2 种方案,在747这个格子只有一种方案。
答案就是 C( 4, 3)*2*2*1
小技巧:求集合数是除数太大,保证精度,需要转换为逆元运算。
AC code:

1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <cmath> 5 #include <map> 6 #define INF 0x3f3f3f3f 7 #define Mod 1000000007 8 #define LL long long 9 using namespace std; 10 const int MAXN = 2e5+10; 11 int aa[MAXN]; 12 map<int, int>mmp; 13 int N, M; 14 LL qpow(LL x, LL n) //求逆元 15 { 16 LL res = 1LL; 17 while(n){ 18 if(n&1) res = (res*x)%Mod; 19 x = (x*x)%Mod; 20 n>>=1; 21 } 22 return res; 23 } 24 25 LL C(LL a, LL b) //求组合数 26 { 27 if(a < b) return 0LL; //无解 28 if(a == b) return 1LL; 29 30 LL U = 1LL, D = 1LL; 31 for(LL i = 1; i <= a; i++) U = U*i%Mod; 32 for(LL j = 1; j <= b; j++) D = D*j%Mod; 33 for(LL j = 1; j <= a-b; j++) D = D*j%Mod; 34 // printf("a:%lld b:%lld ", a, b); 35 // printf("U:%lld D:%lld ", U, D); 36 37 return U*qpow(D, (Mod-2LL))%Mod; 38 } 39 40 bool check(int x) 41 { 42 int aa; 43 while(x){ 44 aa = x%10; 45 if(aa != 4 && aa != 7) return false; 46 x/=10; 47 } 48 return true; 49 } 50 51 int main() 52 { 53 scanf("%d %d", &N, &M); 54 int cnt = 0, num; 55 for(int i = 1; i <= N; i++){ 56 scanf("%d", &num); 57 if(check(num)){ 58 if(mmp[num] != 0) {cnt++;aa[cnt] = num;} 59 mmp[num]++; 60 } 61 } 62 63 LL ans = C(N-cnt, M); 64 65 for(int i = 1; i <= cnt; i++){ 66 ans = (ans*mmp[aa[i]])%Mod; 67 } 68 printf("%lld ", ans); 69 return 0; 70 }