SweetFruits TopCoder - 12141(Matrix-Tree)

SweetFruits TopCoder - 12141(Matrix-Tree)

问题看起来很复杂,不可写,所以先考虑分解一下

假设最后生效的点集为\(V\),那么答案只和\(\sum sweetness[V_i]\)\(|V|\)有关

所以可以考虑对于每一种\(|V|\),先预处理出方案数

得知每一种\(|V|\)的方案数之后,可以用\(\text{meet in the middle}\)法枚举得到\(\sum sweetness[V_i]\leq maxsweetness\)的方案数

方案数是有限制的生成树个数,所以考虑用\(\text{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);
	}
};


posted @ 2020-06-04 16:19  chasedeath  阅读(144)  评论(0编辑  收藏  举报