LOJ6072 「2017 山东一轮集训 Day5」苹果树

Link
先计算出有多少个大小为\(i\)的苹果集合满足其权值和不大于\(lim\)
这可以通过双搜在\(O(n2^{\frac n2})\)的时间复杂度内完成。
那么现在我们就只需要考虑对每个\(i\)求出使得树上恰好有\(i\)个有用苹果的方案数\(f_i\)
考虑先用Kirchhoff定理求出\(g_i\)表示至多有\(i\)个有用的苹果的方案数。
具体而言我们令钦定\(i\)个有用点,它们能和其它的有用点以及坏点连边,好但没用点只能和坏点连边,坏点可以和所有点连边。然后计算其生成树个数。
然后利用容斥可以得出\(f_i=\sum\limits_{j=i}^n{n-i\choose j-i}f_j\)。(这里的\(n\)指好苹果的个数)

#include<cstdio>
#include<cstring>
#include<utility>
#include<algorithm>
#include<functional>
using pi=std::pair<int,int>;
const int N=47,M=1<<20|1,P=1000000007;
int n,x,lim,c1,c2,val[N],C[N][N],f[N],a[N][N],t[N];pi t1[M],t2[M];
int read(){int x;scanf("%d",&x);return x;}
void inc(int&a,int b){a+=b-P,a+=a>>31&P;}
void dec(int&a,int b){a-=b,a+=a>>31&P;}
int mul(int a,int b){return 1ll*a*b%P;}
int pow(int a,int b){int r=1;for(;b;b>>=1,a=mul(a,a))if(b&1)r=mul(a,r);return r;}
void add(int u,int v){dec(a[u][v],1),dec(a[v][u],1),inc(a[u][u],1),inc(a[v][v],1);}
int det()
{
    int r=1;
    for(int i=1;i<n;r=mul(r,a[i][i]),++i)
    {
        for(int j=i+1;j<n;++j)
	{
	    if(!a[j][i]) continue;
	    for(int k=i,x=mul(a[i][i],pow(a[j][i],P-2));k<=n;++k) dec(a[i][k],mul(x,a[j][k]));
	    for(int k=(r=P-r,i);k<=n;++k) std::swap(a[i][k],a[j][k]);
        }
	if(!a[i][i]) return 0;
    }
    return r;
}
int calc(int y)
{
    memset(a,0,sizeof a);
    for(int i=1;i<=y;++i) for(int j=x+1;j<=n;++j) add(i,j);
    for(int i=y+1;i<=n;++i) for(int j=i+1;j<=n;++j) add(i,j);
    return det();
}
void dfs(int now,int sum,int num,int f)
{
    if(sum>lim) return ;
    if(!f&&now==x/2+1) return t1[++c1]={num,sum},void();
    if(f&&now==x+1) return t2[++c2]={num,sum},void();
    dfs(now+1,sum,num,f),dfs(now+1,sum+val[now],num+1,f);
}
int main()
{
    n=read(),lim=read();int ans=0;
    for(int i=1;i<=n;++i) val[i]=read();
    std::sort(val+1,val+n+1,std::greater<int>()),x=std::lower_bound(val+1,val+n+1,-1,std::greater<int>())-val-1;
    for(int i=0;i<=x;++i) for(int j=C[i][0]=1;j<=i;++j) inc(C[i][j]=C[i-1][j-1],C[i-1][j]);
    for(int i=0;i<=x;++i) f[i]=calc(i);
    for(int i=x;~i;--i) for(int j=i+1;j<=x;++j) dec(f[i],mul(C[x-i][j-i],f[j]));
    std::reverse(f,f+x+1),dfs(1,0,0,0),dfs(x/2+1,0,0,1);
    std::sort(t1+1,t1+c1+1,[](const pi&a,const pi&b){return a.second<b.second;});
    std::sort(t2+1,t2+c2+1,[](const pi&a,const pi&b){return a.second<b.second;});
    for(int i=1;i<=c2;++i) ++t[t2[i].first];
    for(int i=1,j=c2;i<=c1;++i)
    {
	while(j&&t1[i].second+t2[j].second>lim) --t[t2[j--].first];
	for(int k=0;k<=n-x/2;++k) inc(ans,mul(f[t1[i].first+k],t[k]));
    }
    printf("%d",ans);
}

猜你喜欢

转载自www.cnblogs.com/cjoierShiina-Mashiro/p/12825228.html
今日推荐