运lucky
题目描述
【问题背景】
zhx 和妹子们玩数数游戏。
【问题描述】
仅包含4或7的数被称为幸运数。一个序列的子序列被定义为从序列中删去若干个数, 剩下的数组成的新序列。两个子序列被定义为不同的当且仅当其中的元素在原始序列中的下标的集合不相等。对于一个长度为 N的序列,共有 2^N个不同的子序列。( 包含一个空序列)。一个子序列被称为不幸运的, 当且仅当其中不包含两个或两个以上相同的幸运数。对于一个给定序列, 求其中长度恰好为 K 的不幸运子序列的个数, 答案 mod 10^9+7 输出。
【输入格式】
第一行两个正整数 N, K, 表示原始序列的长度和题目中的 K。
接下来一行 N 个整数 ai, 表示序列中第 i 个元素的值。
【输出格式】
仅一个数,表示不幸运子序列的个数。( mod 10^9+7)
【样例输入】
3 2
1 1 1
【样例输出】
3
【样例输入】
4 2
4 7 4 7
【样例输出】
4
【样例解释】
对于样例 1,每个长度为 2 的子序列都是符合条件的。
对于样例 2,4个不幸运子序列元素下标分别为:{1, 2}, {3, 4}, {1, 4}, {2, 3}。注意下标集{1, 3}对应的子序列不是“不幸运”的, 因为它包含两个相同的幸运数4.
【数据规模与约定】
对于50%的数据, 1 ≤N ≤ 16。
对于70%的数据, 1 ≤ N ≤ 1000, ai ≤ 10000。
对于100%的数据, 1 ≤ N ≤ 100000,K ≤ N, 1 ≤ ai ≤ 109。
主要是看懂题,会打暴力,就能拿50分
首先我们找到序列中的幸运数,对于只出现一次的幸运数,我们把它当做非幸运数处理,这样我们就得到tot种幸运数
还剩下n2=n-sum个非幸运数,
f[tot][i]可用dp求出f[i][j]表示前i种幸运数中选j个数的方案数,对于每一种幸运数,要么选或者不选,
f[i][j]=f[i-1][j]+f[i-1][j-1]*cnt[i] cnt[i]表示第i种幸运数的个数
组合数n2,K-i都比较大,用阶乘求,求逆元然后求组合数
#include<iostream> #include<cstdio> #include<cstring> #include<map> #include<cmath> #define maxn 100005 #define mod 1000000007 #define LL long long using namespace std; int n,K,n2; int cnt=0,num[1505]; int tot=0,luck[1505]; int p[maxn]; map<int,int> mp; LL a[maxn],c[maxn],f[maxn],jc[maxn]; bool judge(LL x) { int t; while(x){ t=x%10; if(t!=4&&t!=7) return 0; x/=10; } return 1; } LL exgcd(LL a,LL b,LL &x,LL &y) { if(b==0){ x=1; y=0; return a; } LL ans=exgcd(b,a%b,x,y); LL t=x; x=y; y=t-a/b*y; return ans; } LL ny(LL n,LL m) { LL x,y; exgcd(n,m,x,y); return (m+x%m)%m; } LL getc(int x) { if(n2==0){ if(x==0) return 1; else return 0; } LL x0,x1; x0=ny((LL)jc[n2-x],(LL)mod); x1=ny((LL)jc[x],(LL)mod); LL ans=(jc[n2]%mod*x0%mod)%mod; ans=(ans%mod*x1%mod)%mod; return ans; } void pre(int n) { jc[0]=1; for(int i=1;i<=n;i++) jc[i]=(jc[i-1]*i%mod)%mod; } void dp() { f[0]=1; for(int i=1;i<=tot;i++){ for(int j=min(K,tot);j>=1;j--) f[j]=f[j]%mod+f[j-1]*luck[i]%mod; } } int main() { scanf("%d%d",&n,&K); for(int i=1;i<=n;i++){ scanf("%lld",&a[i]); if(judge(a[i])==1){ if(mp.count(a[i])==0) mp[a[i]]=++cnt; num[mp[a[i]]]++; } } int Sum=0; for(int i=1;i<=cnt;i++) if(num[i]>=2){ tot++; luck[tot]=num[i]; Sum+=luck[tot]; } n2=n-Sum; dp();pre(n2); LL ans=0; for(int i=0;i<=min(K,tot);i++){ ans+=(f[i]%mod*getc(K-i)%mod)%mod; } ans=ans%mod; printf("%lld",ans); //while(1); return 0; }