E题当时比赛的时候理解错题意了,以为是数字的位数是k,后来看题解才知道是选k个数组,取得时候先把数分成两组,一组是神仙数,另一种是非神仙数,一共选k个,选i个神仙数和k-i个非神仙数, 但是神仙数不能重复选,就选出所有神仙数(神仙数很少),然后用dp[i][j]=dp[i-1][j]+dp[i-1][j-1]*num[a[i]],a[i]是神仙数。代码:
#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\n",ans); }