zoukankan      html  css  js  c++  java
  • 【BZOJ5315】[JSOI2018]防御网络(动态规划,仙人掌)

    【BZOJ5315】[JSOI2018]防御网络(动态规划,仙人掌)

    题面

    BZOJ
    洛谷

    题解

    显然图是仙人掌。
    题目给了斯坦纳树就肯定不是斯坦纳树了,,,,
    总不可能真让你(2^n)枚举点集再来一个至少(2^n*n)的斯坦纳树吧。。。
    现在对于每一条边考虑贡献。
    如果这条边是不在环内,那么这条边被选当且仅当其子树内外都有点备选,这个随便算算就知道贡献了。
    然后就是环上的边,只考虑这个环,如果一个点的子树内选择了点的话就把环上这个点给标记出来,那么最后选择的东西就一定是整个环的长度减去相邻两个被选中的点的最大距离。
    那么这样子就可以把每个环单独拎出来考虑这个环上的所有边的答案。
    枚举每一个最大的可删去的长度,设(f_x)表示任意一对选择的点的最大长度不超过(x)的方案数。
    那么对于(x)而言,方案数就是(f_x-f_{x-1})
    因为是一个环,断环成链后枚举链上最靠左的被选择的点,这样子可以忽略断开后首尾直接的关系。
    剩下的部分直接(dp),设(g_i)表示当前选择了第(i)个点,并且第(i)个点强制被选择的方案数,转移的时候强迫相邻点的距离不超过枚举的长度(x),这个东西可以用前缀和优化。
    那么枚举长度、枚举左端点再(dp),所以这部分的复杂度是(O(n^3))的。

    #include<iostream>
    #include<cstdio>
    #include<vector>
    using namespace std;
    #define MAX 205
    #define MOD 1000000007
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    int fpow(int a,int b){int s=1;while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}return s;}
    struct Line{int v,next;}e[MAX<<2];
    int h[MAX],cnt=2;bool vis[MAX<<2];
    inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
    int n,m,size[MAX],ans,bin[MAX],fr[MAX],fa[MAX];
    vector<int> dn,up;
    int S[MAX],top,sz[MAX],dep[MAX];
    void Get(int u,int R)
    {
    	S[top=1]=u;
    	for(int j=u;j!=R;j=fa[j])
    		vis[fr[j]>>1]=true,S[++top]=fa[j];
    }
    void dfs(int u,int ff)
    {
    	size[u]=1;fa[u]=ff;dep[u]=dep[ff]+1;int R=0;
    	for(int i=h[u];i;i=e[i].next)
    	{
    		int v=e[i].v;if(v==ff)continue;
    		if(size[v]){if(dep[v]<dep[u])Get(u,R=v);
    			vis[i>>1]=true;continue;}
    		fr[v]=i;dfs(v,u);size[u]+=size[v];
    	}
    	for(int i=h[u];i;i=e[i].next)
    	{
    		int v=e[i].v;if(v==ff)continue;
    		if(vis[i>>1])continue;
    		ans=(ans+1ll*(bin[size[v]]-1)*(bin[n-size[v]]-1))%MOD;
    	}
    	if(R)dn.push_back(u),up.push_back(R);
    }
    int g[MAX],f[MAX],ss[MAX];
    void Solve(int u,int R)
    {
    	Get(u,R);
    	for(int i=1;i<=top;++i)sz[i]=size[S[i]];
    	for(int i=top;i>1;--i)sz[i]-=sz[i-1];
    	sz[top]+=n-size[S[top]];
    	for(int i=1;i<=top;++i)f[i]=0;
    	for(int l=1;l<=top;++l)
    	{
    		for(int i=1;i<=l;++i)
    		{
    			for(int j=1;j<=top;++j)ss[j]=g[j]=0;
    			g[i]=ss[i]=bin[sz[i]]-1;
    			for(int j=i+1;j<=top;++j)
    			{
    				int L=max(1,j-l),R=j-1,d=bin[sz[j]]-1;
    				g[j]=1ll*d*(ss[R]-ss[L-1]+MOD)%MOD;
    				ss[j]=(ss[j-1]+g[j])%MOD;
    			}
    			int L=max(top-l+i,i+1);
    			f[l]=(1ll*f[l]+ss[top]-ss[L-1]+MOD)%MOD;
    		}
    	}
    	for(int i=1;i<=top;++i)
    		ans=(ans+1ll*(top-i)*(f[i]+MOD-f[i-1]))%MOD;
    	return;
    }
    int main()
    {
    	n=read();m=read();
    	bin[0]=1;for(int i=1;i<=n;++i)bin[i]=(bin[i-1]<<1)%MOD;
    	for(int i=1;i<=m;++i)
    	{
    		int u=read(),v=read();
    		Add(u,v);Add(v,u);
    	}
    	dfs(1,0);
    	for(int i=0;i<dn.size();++i)Solve(dn[i],up[i]);
    	ans=1ll*ans*fpow(bin[n],MOD-2)%MOD;
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    鸿蒙轻内核M核源码分析:数据结构之任务就绪队列
    Elasticsearch数据库优化实战:让你的ES飞起来
    还不会使用分布式锁?教你三种分布式锁实现的方式
    云小课 | 大数据融合分析:GaussDW(DWS)轻松导入MRS-Hive数据源
    JavaScript 空间坐标
    HttpWatch网络抓包工具的使用
    安卓Fragment和Activity之间的数据通讯
    Android MVP模式
    Android从服务端获取json解析显示在客户端上面
    JavaWeb网上商城的反思
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10416830.html
Copyright © 2011-2022 走看看