51nod-1446-价值限制树
51nod-1446-价值限制树
真·一调一下午。
题意:给\(n\)个点,每个点有权值\(a_i\),若\(a_i=-1\)称这个点\(not good\),否则是\(good\)的。形成任意一棵生成树后若\(good\)的点相邻的点有\(good\)点,则称该点是\(great\)的。生成树的价值是所有\(great\)的点的权值和。给定\(maxval\)值,求所有生成树价值不超过\(maxval\)的生成树个数。
题解:显然需要建图跑矩阵树定理。可以发现一个性质,就是在\(good\)的点中选出几个点作为\(great\)点之后,形成的生成树方案是一定的。所以设\(f[i]\)为选出了\(i\)个点作为\(great\)点的生成树方案,发现\(f[i]\)并不能建图后直接求。不妨设\(h[i]\)表示最多有\(i\)个点是\(great\)点的生成树种类,则只需将\(great\)点相互连边,不是\(good\)的点向其他点连边,然后跑矩阵树定理即可求\(h[i]\)。
由于\(h[i]\)的状况是有i个点可以互相连通形成\(great\)点的生成树方案数,实际上可能若这\(i\)个点中某个点成为叶子节点,且父节点是\(not good\)的节点,那么会不满\(i\)个,此时会有\(j\)个节点被选出,这样的情况总和是\(\sum^{i-1}_{j=0}C_{i}^{j}f[j]\),于是由容斥定理:
可以计算出\(f[i]\) 。
在每种\(f[i]\)的情况下,需要满足价值不超过\(maxval\)的限制条件。也就是我们在所有\(good\)的点中选i个使其权值和不超过\(maxval\)。
设其种类数为\(g[i]\),则可以使用折半搜索\((n≤40)\)计算出结果。折半搜索的模版是:P4799世界冰球锦标赛
于是我们要求的总答案即为\(\sum_{i=0}^{gd}f[i]g[i]\)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mod (ll)(1e9+7)
const int maxn=3e5+10;
int t,n,maxval,gd,ngd;
ll yuan[50],f[50],g[50],h[50];
ll gdb[50],bd[50];
bool good[50];
int qian[50][maxn],hou[50][maxn],cntq[50],cnth[50];//vector
void pre(){
memset(yuan,0,sizeof(yuan));
memset(f,0,sizeof(f));memset(g,0,sizeof(g));
memset(h,0,sizeof(h));
memset(gdb,0,sizeof(gdb));
memset(bd,0,sizeof(bd));
memset(good,0,sizeof(good));
gd=ngd=0;
memset(qian,0,sizeof(qian));memset(hou,0,sizeof(hou));
memset(cntq,0,sizeof(cntq));
memset(cnth,0,sizeof(cnth));
}
struct matrix{
ll ma[50][50];
void pre(){memset(ma,0,sizeof(ma));}
}du;
ll gauss(){
n--;
ll ans=1;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
while(du.ma[j][i]){
ll tmp=du.ma[i][i]/du.ma[j][i];
for(int k=i;k<=n;k++) du.ma[i][k]=((du.ma[i][k]-tmp*du.ma[j][k]%mod)%mod+mod)%mod,swap(du.ma[i][k],du.ma[j][k]);
ans=-ans;
}
}
ans=(ans*du.ma[i][i]%mod+mod)%mod;
}
n++;
return (ans+mod)%mod;
}
void solh(){
for(int i=0;i<=gd;i++){
du.pre();
int now1=i,now2=gd-i;
for(int j=1;j<=now1;j++){
for(int k=j+1;k<=now1;k++){
du.ma[j][k]=-1,du.ma[k][j]=-1;
du.ma[j][j]++,du.ma[k][k]++;
}
}
for(int j=gd+1;j<=n;j++){
for(int k=1;k<j;k++){
du.ma[j][j]++,du.ma[k][k]++;
du.ma[j][k]=-1,du.ma[k][j]=-1;
}
}
h[i]=gauss();
}
}
void dfsq(int qian1,int hou1,int val,int ge){
if(val>maxval) return;
if(qian1==hou1){
if(val+yuan[gdb[qian1]]<=maxval) qian[ge+1][++cntq[ge+1]]=(val+yuan[gdb[qian1]]);
qian[ge][++cntq[ge]]=val;
return;
}
dfsq(qian1+1,hou1,(val+yuan[gdb[qian1]]),ge+1);
dfsq(qian1+1,hou1,val,ge);
}
void dfsh(int qian1,int hou1,int val,int ge){
if(val>maxval) return;
if(qian1==hou1){
if(val+yuan[gdb[qian1]]<=maxval) hou[ge+1][++cnth[ge+1]]=(val+yuan[gdb[qian1]]);
hou[ge][++cnth[ge]]=val;
return;
}
dfsh(qian1+1,hou1,(val+yuan[gdb[qian1]]),ge+1);
dfsh(qian1+1,hou1,val,ge);
}
void solg(){
ll mid=gd/2;
g[0]=1;
if(gd==1){
if(yuan[gdb[1]]<=maxval) g[1]=1;
return;
}
else if(gd==0) return;
g[0]=0;
dfsq(1,mid,0,0);dfsh(mid+1,gd,0,0);
for(int i=1;i<=gd;i++){
sort(qian[i]+1,qian[i]+cntq[i]+1);
sort(hou[i]+1,hou[i]+cnth[i]+1);
}
for(int i=0;i<=gd;i++){
for(int j=0;j<=i;j++){
int nowq=j,nowh=i-j;
for(int p=1;p<=cntq[nowq];p++){
ll sheng=maxval-qian[nowq][p];
ll biao=upper_bound(hou[nowh]+1,hou[nowh]+cnth[nowh]+1,sheng)-hou[nowh]-1;
g[i]=(g[i]+biao)%mod;
}
}
}
}
int cm[50][50];
signed main(){
cin>>t;
cm[1][1]=1;
for(int i=0;i<=45;i++) cm[i][0]=1;
for(int i=2;i<=45;i++){
for(int j=1;j<=i;j++){
cm[i][j]=(cm[i-1][j]+cm[i-1][j-1])%mod;
}
}
while(t--){
cin>>n>>maxval;
pre();
for(int i=1;i<=n;i++){
cin>>yuan[i];
if(yuan[i]>=0) gdb[++gd]=i,good[i]=1;
else bd[++ngd]=i,good[i]=0;
}
solh();
for(int i=0;i<=gd;i++){
f[i]=h[i];
for(int j=0;j<i;j++) f[i]=((f[i]-(ll)cm[i][j]*f[j]%mod)%mod+mod)%mod;
}
solg();
ll ans=0;
for(int i=0;i<=gd;i++) ans=(ans+(ll)f[i]*g[i]%mod)%mod;
cout<<ans<<endl;
}
return 0;
}

浙公网安备 33010602011771号