这个题其实就是个dp(类似背包),但是一些细节还是让我做了一晚上。
这个题学习了组合数取模(逆元法)
补充知识:逆元的求法
(a/b) mod p=a*(b逆) mod p
b*x=1(mod p) x就是b的逆元
而b逆可以利用扩展欧几里德或欧拉函数求得:
1).扩展欧几里德:b*x+p*y=1 有解,x就是所求
2).欧拉函数:b^(p-1)=1(mod p),故b*b^(p-2)=1(mod p),所以x=b^(p-2)
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#define ll long long
#define oo 1000000007
#define min(a,b) (a)<(b)?(a):(b)
using namespace std;
map <int,int> a;
int f[10005];
ll g[1500][1500],c[100005],s[10005];
ll xx,y;
void excuild(ll a,ll b)
{
ll tmp;
if(b==0){xx=1;y=0;return;}
excuild(b,a%b);
tmp=xx;
xx=y;
y=tmp - a/b*y;
}
int main()
{
int h=0,t=1; f[1]=0;
while (h<t){
int i=f[++h]; if (i>100000000) continue;
f[++t]=i*10+4; f[++t]=i*10+7;
} // 这里f[]记录小于100000000的幸运数(幸运数总数小于10005,大家可以自己算一算)
for (int i=2;i<=t;i++) a[f[i]]=i-1;
int n,k,x,y; scanf("%d%d",&n,&k);
for (int i=1;i<=n;i++){
scanf("%d",&x);
if (a.find(x)==a.end()) y=0;
else y=a[x];
s[y]++;
}
int sum=0; g[0][0]=1;
for (int i=1;i<=t;i++) if (s[i]){
sum++; g[sum][0]=1;
for (int j=1;j<=sum;j++){
g[sum][j]=(g[sum-1][j]+g[sum-1][j-1]*s[i])%oo;
} //g[sum][j]表示从前sum类幸运数中选出j个的总方法数
}
ll z=1; c[0]=1;
for (int i=s[0];i;i--){
c[i]=z; z=z*i%oo;
excuild(s[0]-i+1,oo);
z=z*xx%oo;
z=(z+oo)%oo;
} //c[]表示组合数C(n,k)(k从0取到n)
ll ans=0;
for (int i=0;i<=(min(sum,k));i++) ans=(ans+g[sum][i]*c[k-i])%oo;
printf("%d\n",(ans+oo)%oo);
return 0;
}
这里C(n,k)如果要分开求的话。最好这样做(这样只调用一次excuild函数)
void excuild(ll a,ll b)
{
ll tmp;
if(b==0){x=1;y=0;return;}
excuild(b,a%b);
tmp=x;
x=y;
y=tmp - a/b*y;
}
ll c(ll n,ll k)
{
ll a=1,b=1,tmp=k,i;
for(i=0;i<tmp;i++)
{
a=a*n%inf;
b=b*k%inf;
n--;k--;
}
excuild(inf,b);
a=a*y%inf;
if(a<0)a+=inf;
return a;
}
我就是在这里一直TLE,T死我啦(囧)
搓代码留纪念
int x,y;
void excuild(ll a,ll b)
{
ll tmp;
if(b==0){x=1;y=0;return;}
excuild(b,a%b);
tmp=x;
x=y;
y=tmp - a/b*y;
}
ll c(ll a,ll b){
if(b==0)
return 1;
else {
excuild(b,inf);
ll xx=x;
ll tem=(c(a-1,b-1)*a%inf)*xx%inf;
while(tem<0)
tem+=inf;
return tem;
}
}
由于excuild函数调用太多T了。
下面代码是快速幂求逆元的方法
ll mul(ll x,int y)
{
ll z=1;
while (y){
if (y&1) z=(z*x)%inf;
y/=2; x=(x*x)%inf;
}
return z;
}
ll z=1; c[0]=1;
for (int i=n;i;i--){
c[i]=z; z=z*i%inf;
z=z*mul(n-i+1,inf-2)%inf;
z=(z+inf)%inf;
}