Link
先计算出有多少个大小为(i)的苹果集合满足其权值和不大于(lim)。
这可以通过双搜在(O(n2^{frac n2}))的时间复杂度内完成。
那么现在我们就只需要考虑对每个(i)求出使得树上恰好有(i)个有用苹果的方案数(f_i)。
考虑先用Kirchhoff定理求出(g_i)表示至多有(i)个有用的苹果的方案数。
具体而言我们令钦定(i)个有用点,它们能和其它的有用点以及坏点连边,好但没用点只能和坏点连边,坏点可以和所有点连边。然后计算其生成树个数。
然后利用容斥可以得出(f_i=sumlimits_{j=i}^n{n-ichoose j-i}f_j)。(这里的(n)指好苹果的个数)
#include<cstdio>
#include<cstring>
#include<utility>
#include<algorithm>
#include<functional>
using pi=std::pair<int,int>;
const int N=47,M=1<<20|1,P=1000000007;
int n,x,lim,c1,c2,val[N],C[N][N],f[N],a[N][N],t[N];pi t1[M],t2[M];
int read(){int x;scanf("%d",&x);return x;}
void inc(int&a,int b){a+=b-P,a+=a>>31&P;}
void dec(int&a,int b){a-=b,a+=a>>31&P;}
int mul(int a,int b){return 1ll*a*b%P;}
int pow(int a,int b){int r=1;for(;b;b>>=1,a=mul(a,a))if(b&1)r=mul(a,r);return r;}
void add(int u,int v){dec(a[u][v],1),dec(a[v][u],1),inc(a[u][u],1),inc(a[v][v],1);}
int det()
{
int r=1;
for(int i=1;i<n;r=mul(r,a[i][i]),++i)
{
for(int j=i+1;j<n;++j)
{
if(!a[j][i]) continue;
for(int k=i,x=mul(a[i][i],pow(a[j][i],P-2));k<=n;++k) dec(a[i][k],mul(x,a[j][k]));
for(int k=(r=P-r,i);k<=n;++k) std::swap(a[i][k],a[j][k]);
}
if(!a[i][i]) return 0;
}
return r;
}
int calc(int y)
{
memset(a,0,sizeof a);
for(int i=1;i<=y;++i) for(int j=x+1;j<=n;++j) add(i,j);
for(int i=y+1;i<=n;++i) for(int j=i+1;j<=n;++j) add(i,j);
return det();
}
void dfs(int now,int sum,int num,int f)
{
if(sum>lim) return ;
if(!f&&now==x/2+1) return t1[++c1]={num,sum},void();
if(f&&now==x+1) return t2[++c2]={num,sum},void();
dfs(now+1,sum,num,f),dfs(now+1,sum+val[now],num+1,f);
}
int main()
{
n=read(),lim=read();int ans=0;
for(int i=1;i<=n;++i) val[i]=read();
std::sort(val+1,val+n+1,std::greater<int>()),x=std::lower_bound(val+1,val+n+1,-1,std::greater<int>())-val-1;
for(int i=0;i<=x;++i) for(int j=C[i][0]=1;j<=i;++j) inc(C[i][j]=C[i-1][j-1],C[i-1][j]);
for(int i=0;i<=x;++i) f[i]=calc(i);
for(int i=x;~i;--i) for(int j=i+1;j<=x;++j) dec(f[i],mul(C[x-i][j-i],f[j]));
std::reverse(f,f+x+1),dfs(1,0,0,0),dfs(x/2+1,0,0,1);
std::sort(t1+1,t1+c1+1,[](const pi&a,const pi&b){return a.second<b.second;});
std::sort(t2+1,t2+c2+1,[](const pi&a,const pi&b){return a.second<b.second;});
for(int i=1;i<=c2;++i) ++t[t2[i].first];
for(int i=1,j=c2;i<=c1;++i)
{
while(j&&t1[i].second+t2[j].second>lim) --t[t2[j--].first];
for(int k=0;k<=n-x/2;++k) inc(ans,mul(f[t1[i].first+k],t[k]));
}
printf("%d",ans);
}