SweetFruits TopCoder - 12141(Matrix-Tree)
问题看起来很复杂,不可写,所以先考虑分解一下
假设最后生效的点集为(V),那么答案只和(sum sweetness[V_i])和(|V|)有关
所以可以考虑对于每一种(|V|),先预处理出方案数
得知每一种(|V|)的方案数之后,可以用( ext{meet in the middle})法枚举得到(sum sweetness[V_i]leq maxsweetness)的方案数
方案数是有限制的生成树个数,所以考虑用( ext{Matrix-Tree})求
限定有(a)个点生效,(b)个点不生效,(c)个点是(-1)
那么可能出现的边是(a-a,a-c,b-c)三种
但是我们无法保证(a)中的点一定生效,所以可以用容斥/二项式反演得到
#include<bits/stdc++.h>
using namespace std;
#define Mod1(x) ((x>=P)&&(x-=P))
#define Mod2(x) ((x<0)&&(x+=P))
#define reg register
typedef long long ll;
#define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)
#define pb push_back
template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }
char IO;
int rd(){
int s=0;
int f=0;
while(!isdigit(IO=getchar())) if(IO=='-') f=1;
do s=(s<<1)+(s<<3)+(IO^'0');
while(isdigit(IO=getchar()));
return f?-s:s;
}
const int N=50,P=1e9+7;
ll qpow(ll x,ll k=P-2) {
ll res=1;
for(;k;k>>=1,x=x*x%P) if(k&1) res=res*x%P;
return res;
}
int n,m;
struct Mat{
int a[N][N];
Mat(){ memset(a,0,sizeof a); }
int Det(int n){ // 用于Matrix-Tree的
static int G[N][N];
rep(i,1,n) rep(j,1,n) G[i][j]=a[i][j];
int res=1;
rep(i,1,n) {
if(!G[i][i]) rep(j,i+1,n) if(G[j][i]){ res=P-res; swap(G[i],G[j]); break; }
if(!G[i][i]) continue;
ll Inv=qpow(a[i][i]);
rep(j,i+1,n) {
ll t=a[j][i]*Inv%P;
rep(k,i,n) a[j][k]=(a[j][k]-1ll*a[i][k]*t%P+P)%P;
}
}
rep(i,1,n) res=1ll*res*a[i][i]%P;
return res;
}
};
int w[N],G[N][N],C[N][N];
void Init(){
rep(i,0,N-1) rep(j,C[i][0]=1,i) C[i][j]=(C[i-1][j-1]+C[i-1][j])%P;
rep(i,0,n) {
Mat T;
rep(j,1,m) { // -1
rep(k,1,n+m) T.a[j][k]=-1;
T.a[j][j]=n+m-1;
}
rep(j,m+1,m+i) { // 生效
rep(k,1,m+i) if(j!=k) T.a[j][k]=-1;
T.a[j][j]=m+i-1;
}
rep(j,m+i+1,m+n) { // 不生效
rep(k,1,m) T.a[j][k]=-1;
T.a[j][j]=m;
}
w[i]=T.Det(n+m-1);
}
rep(i,0,n) rep(j,0,i-1) w[i]=(w[i]-1ll*C[i][j]*w[j]%P+P)%P; // 容斥/二项式反演
}
int val[N];
vector <int> st[N/2];
int Meet_In_The_Middle(int Max){
int ans=0,mid=n/2;
rep(i,0,mid) st[i].clear();
rep(S,0,(1<<mid)-1) {
int c=0,s=0;
rep(i,0,mid-1) if(S&(1<<i)) s+=val[i],c++;
if(s<=Max) st[c].pb(s);
}
rep(i,0,mid) sort(st[i].begin(),st[i].end());
rep(S,0,(1<<(n-mid))-1) {
int c=0,s=0;
rep(i,0,n-mid-1) if(S&(1<<i)) s+=val[i+mid],c++;
if(s>Max) continue;
rep(j,0,mid) {
int x=upper_bound(st[j].begin(),st[j].end(),Max-s)-st[j].begin();
if(x) ans=(ans+1ll*x*w[c+j])%P;
}
}
return ans;
}
class SweetFruits {
public:
int countTrees(vector <int> Val, int Max) {
sort(Val.begin(),Val.end(),greater <int> ());
m=0; while(Val.size() && *Val.rbegin()==-1) m++,Val.pop_back();
n=Val.size();
rep(i,0,n-1) val[i]=Val[i];
Init();
return Meet_In_The_Middle(Max);
}
};