51Nod1446 限制价值树

讲课时候一点儿都没懂

 

分成两个部分:

找到所有满足sum<=mx的集合,即枚举哪些是great的、统计每个great的集合对应多少个树

发现,第二个部分只和great集合大小有关

 

具体的

第一个部分:折半爆搜+sort+双指针,得到g[i]大小为i的great集合个数

第二部分:

f[i]表示钦定i个是great的生成树个数

答案=∑f[i]*g[i]

求f[i]?

不妨钦定1~i为great

完全图,把所有连接至少一个good的边去掉,矩阵树定理求生成树

这样得到了至多有i个great的个数h

减去孤立的:

则f[i]=h-∑0<=j<i,f[j]*C(i,j)

 

即可。

 

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define fi first
#define se second
#define mk(a,b) make_pair(a,b)
#define numb (ch^'0')
#define pb push_back
#define solid const auto &
#define enter cout<<endl
#define pii pair<int,int>
using namespace std;
typedef long long ll;
template<class T>il void rd(T &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');}

namespace Miracle{
const int N=44;
const int mod=1e9+7;
const int M=(1<<20)+233;
int n,mx,m;
int C[N][N];
int ad(int x,int y){
    return x+y>=mod?x+y-mod:x+y;
}
int mul(int x,int y){
    return (ll)x*y%mod;
}
int qm(int x,int y){
    int ret=1;
    while(y){
        if(y&1) ret=(ll)ret*x%mod;
        x=(ll)x*x%mod;
        y>>=1;
    }
    return ret;
}

int val[N];
int pre[(1<<20)+233][21];
struct po{
    int s,sz;
    po(){}
    po(int ss,int size){s=ss;sz=size;}
    bool friend operator <(po a,po b){
        return a.s<b.s;
    }
}p[2][M];
int cnt[2];
void dfs(int x,int lim,int lp,int sz,int sum){
    if(sum>mx) return;
    if(x==lim+1){
        ++cnt[lp];
        p[lp][cnt[lp]]=po(sum,sz);return;
    }
    if(val[x]<0) dfs(x+1,lim,lp,sz,sum);
    else{
        dfs(x+1,lim,lp,sz,sum);
        dfs(x+1,lim,lp,sz+1,sum+val[x]);
    }
}
int t[N][N];
int guass(int f[N][N],int n){
    // cout<<" guass "<<endl;
    // for(reg i=1;i<=n;++i){
    //     prt(f[i],1,n);
    // }cout<<endl;
    int tmp=1;
    for(reg i=1;i<=n;++i){
        int id=0;
        for(reg j=i;j<=n;++j){
            if(f[j][i]) {
                id=j;break;
            }
        }
        if(id==0) return 0;
        if(id!=i){
            tmp=-tmp;
            for(reg j=1;j<=n;++j) swap(f[i][j],f[id][j]);
        }
        int inv=qm(f[i][i],mod-2);
        for(reg j=i+1;j<=n;++j){
            if(f[j][i]){
                int c=mul(f[j][i],inv);
                for(reg k=i;k<=n;++k){
                    f[j][k]=ad(f[j][k],mod-mul(c,f[i][k]));
                }
            }
        }
    }
    ll ret=ad(mod,tmp);
    for(reg i=1;i<=n;++i) ret=mul(ret,f[i][i]);return ret;
}
int g[N],f[N];
void clear(){
    memset(g,0,sizeof g);
    memset(f,0,sizeof f);
    memset(pre,0,sizeof pre);
    cnt[0]=cnt[1]=0;
    m=0;
}
int main(){
    int T;rd(T);
    C[0][0]=1;
    for(reg i=1;i<=42;++i){
        C[i][0]=1;
        for(reg j=1;j<=i;++j){
            C[i][j]=ad(C[i-1][j],C[i-1][j-1]);
        }
    }
    while(T--){
        rd(n);rd(mx);
        for(reg i=1;i<=n;++i) {
            rd(val[i]);
            if(val[i]>=0) ++m;
        }
        int half=n/2;
        dfs(1,half,0,0,0);
        sort(p[0]+1,p[0]+cnt[0]+1);
        for(reg i=1;i<=cnt[0];++i){
            memcpy(pre[i],pre[i-1],sizeof pre[i-1]);
            pre[i][p[0][i].sz]++;
        }
        dfs(half+1,n,1,0,0);
        sort(p[1]+1,p[1]+cnt[1]+1);
        int ptr=cnt[0];
        for(reg i=1;i<=cnt[1];++i){
            while(ptr>0&&p[1][i].s+p[0][ptr].s>mx) --ptr;
            for(reg j=0;j<=half;++j){
                g[j+p[1][i].sz]=ad(g[j+p[1][i].sz],pre[ptr][j]);
            }
        }

        for(reg i=0;i<=m;++i){
            memset(t,0,sizeof t);
            for(reg j=1;j<=i;++j){t[j][j]=i-1+n-m;}
            for(reg j=i+1;j<=m;++j){t[j][j]=n-m;}
            for(reg j=m+1;j<=n;++j){t[j][j]=n-1;}
            for(reg j=1;j<=n;++j){
                for(reg k=1;k<=n;++k){
                    if(j==k) continue;
                    if(j<=i&&i<k&&k<=m) continue;
                    if(i<j&&j<=m&&k<=i) continue;
                    if(i<k&&k<=m&&i<j&&j<=m) continue;
                    // cout<<" add "<<j<<" "<<k<<endl;
                    t[j][k]=ad(t[j][k],mod-1);
                }
            }
            f[i]=guass(t,n-1);
            // cout<<" st "<<f[i]<<endl;
            for(reg j=0;j<i;++j){
                f[i]=ad(f[i],mod-mul(C[i][j],f[j]));
            }
        }
        ll ans=0;
        // prt(g,0,m);
        // prt(f,0,m);

        for(reg i=0;i<=m;++i){
            ans=ad(ans,mul(g[i],f[i]));
        }
        printf("%lld\n",ans);
        if(T) clear();
    }
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
*/

 

posted @ 2019-05-17 18:09  *Miracle*  阅读(263)  评论(0编辑  收藏  举报