• LOJ6072苹果树


    https://loj.ac/problem/6072

    虽然结合了很多算法,但是一步一步地推一下还不算太难的一道题。

    首先考虑枚举枚举有用的苹果的集合,然后去算生成树个数。

    先考虑怎么计算生成树个数。

    发现可以使用matrix-tree。

    所有有用点可以和有用点以及坏点连边,所有不是坏点的无用点只能和坏点连边,坏点可以和所有点连边。

    然后跑一下matrix-tree。但是这样算出来的是至多S这个集合为有用点的方案数,需要套一个容斥。

    分析上述过程,发现需要的信息只有好点的个数。

    因此可以只需要计算出大小为k的和<lim合法集合有多少即可,这个显然可以meet in the middle。

    #include<bits/stdc++.h>
    #define N 44
    #define M 1100000
    #define ll long long
    using namespace std;
    inline int read()
    {
    	char ch=0;
    	int x=0,flag=1;
    	while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
    	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*flag;
    }
    const int mo=1e9+7;
    int ksm(int x,int k)
    {
    	int ans=1;
    	while(k)
    	{
    		if(k&1)ans=1ll*ans*x%mo;
    		k>>=1;x=1ll*x*x%mo;
    	}
    	return ans;
    }
    int inv(int x){return ksm((x%mo+mo)%mo,mo-2);}
    int a[N][N];
    int matrix_tree(int n)
    {
    	int ans=1;
    	for(int i=1;i<=n;i++)if(!a[i][i])return 0;
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=i+1;j<=n;j++)
    		{
    			int t=1ll*a[j][i]*inv(a[i][i])%mo;
    			for(int k=i;k<=n;k++)a[j][k]=(a[j][k]-(1ll*t*a[i][k]%mo))%mo;
    		}
    		ans=1ll*ans*a[i][i]%mo;
    	}
    	return (ans%mo+mo)%mo;
    }
    int w[N],sz[N],dp[N],ans[N],c[N][N],f[N/2][M];
    bool cmp(int a,int b){return a>b;}
    int main()
    {
    	int n=read(),lim=read(),cnt=0,res=0;
    	for(int i=1;i<=n;i++)w[i]=read(),cnt+=(w[i]==-1);sort(w+1,w+n+1,cmp);
    	int m=n-cnt,mid=m/2;
    	for(int s=0;s<(1<<mid);s++)
    	{
    		int num=0,tot=0;
    		for(int i=1;i<=mid;i++)if(1<<(i-1)&s)num++,tot+=w[i];
    		if(tot<=lim)f[num][++sz[num]]=tot;
    	}
    	for(int i=0;i<=mid;i++)sort(f[i]+1,f[i]+sz[i]+1);
    	for(int s=0;s<(1<<(m-mid));s++)
    	{
    		int num=0,tot=0;
    		for(int i=1;i<=m-mid;i++)if(1<<(i-1)&s)num++,tot+=w[i+mid];
    		for(int i=0;i<=mid;i++)dp[i+num]=(dp[i+num]+(upper_bound(f[i]+1,f[i]+sz[i]+1,lim-tot)-f[i]-1))%mo;
    	}
    	for(int i=0;i<=n;i++){c[i][0]=1;for(int j=1;j<=n;j++)c[i][j]=(c[i-1][j-1]+c[i-1][j])%mo;}
    	for(int o=0;o<=m;o++)
    	{
    		for(int i=1;i<=o;i++)for(int j=1;j<=n;j++)if(i==j)a[i][j]=(o-1)+cnt;else a[i][j]=-(j<=o||j>m);
    		for(int i=o+1;i<=m;i++)for(int j=1;j<=n;j++)if(i==j)a[i][j]=cnt;else a[i][j]=-(j>m);
    		for(int i=m+1;i<=n;i++)for(int j=1;j<=n;j++)if(i==j)a[i][j]=n-1;else a[i][j]=-1;
    		ans[o]=matrix_tree(n-1);
    		for(int i=0;i<o;i++)ans[o]=(ans[o]-(1ll*c[o][i]*ans[i]%mo))%mo;
    		res=(res+(1ll*dp[o]*ans[o]%mo))%mo;
    	}
    	printf("%d",(res%mo+mo)%mo);
    	return 0;
    }
    
  • 相关阅读:
    1.Apache与Tomcat
    jeeplus 多选框
    GIT 回滚
    jsp 中data 转换 字符串
    Pattern和Matcher中表达式
    web.xml 详细介绍
    $.ajax()方法详解
    My 2016
    如何做好一个保安队长。
    集合之WeakHashMap
  • 原文地址:https://www.cnblogs.com/Creed-qwq/p/10641579.html
Copyright © 2020-2023  润新知