題目
思路
太傻了,並不會拆分問題
由於是完全圖,原問題可以拆分成兩個問題
- 選出 個 點的方案數,記爲
- 個 構成合法生成樹的方案數,記爲
總方案數就是
假設有 個點不是
假設選的 個點爲
那麼剩下的 個點必定和 相連,並且不會連接前 個點
建圖就很清晰了
前面 個點就和 相連,矩陣樹定理求出方案數記爲
表示至多有 個 的方案數
不難得出
用二分搜索即可,合併答案要利用桶
時間複雜度
代碼
#include<set>
#include<map>
#include<stack>
#include<ctime>
#include<cstdio>
#include<queue>
#include<cmath>
#include<vector>
#include<cstring>
#include<climits>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
int read(){
int f=1,x=0;char c=getchar();
while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();}
while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}
return f*x;
}
#define MAXN 40
#define INF 0x3f3f3f3f
#define Mod (int)(1e9+7)
int Add(int x,int y){x+=y;return x>=Mod?x-Mod:x;}
LL a[MAXN+5][MAXN+5],C[MAXN+5][MAXN+5];
LL Pow(LL x,int y){
LL ret=1;
while(y){
if(y&1) ret=ret*x%Mod;
x=x*x%Mod,y>>=1;
}
return ret;
}
LL Det(int n){
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
a[i][j]=(a[i][j]+Mod)%Mod;
n--;
LL ret=1;
for(int i=1;i<=n;i++){
if(!a[i][i]){
for(int j=i+1;j<=n;j++)
if(a[j][i]){
swap(a[i],a[j]),ret=Mod-ret;
break;
}
}
if(!a[i][i])
return 0;
LL Inv=Pow(a[i][i],Mod-2);
for(int j=i+1;j<=n;j++){
LL tmp=a[j][i]*Inv%Mod;
for(int k=i;k<=n;k++)
a[j][k]=(a[j][k]-tmp*a[i][k]%Mod+Mod)%Mod;
}
}
for(int i=1;i<=n;i++)
ret=ret*a[i][i]%Mod;
return ret;
}
void Prepare(){
for(int i=0;i<=MAXN;i++)
C[i][i]=C[i][0]=1;
for(int i=1;i<=MAXN;i++)
for(int j=1;j<i;j++)
C[i][j]=(C[i-1][j]+C[i-1][j-1])%Mod;
return ;
}
vector<pair<int,int> > p,q;
int bar[MAXN+5],val[MAXN+5],f[MAXN+5],g[MAXN+5];
void DFS(int L,int R,int cnt,int v,vector<pair<int,int> > &x){
if(L>R){
x.push_back(make_pair(v,cnt));
return ;
}
DFS(L+1,R,cnt,v,x);
DFS(L+1,R,cnt+1,v+val[L],x);
return ;
}
void Init(){
p.clear(),q.clear();
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
memset(bar,0,sizeof(bar));
return ;
}
int main(){//至多有i個great的個數h
Prepare();
int T=read();
while(T--){
Init();
int n=read(),cnt=0,Max=read();
for(int i=1;i<=n;i++){
val[i]=read();
if(val[i]!=-1)
cnt++;
}
sort(val+1,val+n+1,greater<int>());
for(int t=0;t<=cnt;t++){
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(j>cnt||j<=t)
a[i][j]--,a[j][i]--,a[i][i]++,a[j][j]++;
f[t]=Det(n);
for(int i=0;i<t;i++)
f[t]=(f[t]-C[t][i]*f[i]%Mod+Mod)%Mod;
}
DFS(1,cnt/2,0,0,p);
DFS(cnt/2+1,cnt,0,0,q);
sort(p.begin(),p.end()),sort(q.begin(),q.end());
for(int i=0;i<(int)p.size();i++)
bar[p[i].second]++;
for(int i=0,j=(int)p.size()-1;i<(int)q.size();i++){
while(~j&&q[i].first+p[j].first>Max)
bar[p[j--].second]--;
for(int k=0;k<=cnt/2;k++)
g[q[i].second+k]=Add(g[q[i].second+k],bar[k]);
}
LL ans=0;
for(int i=0;i<=cnt;i++)
ans=(ans+1ll*f[i]*g[i])%Mod;
printf("%lld\n",ans);
}
return 0;
}