您的位置:首页 > 理论基础 > 计算机网络

bzoj 5315: [Jsoi2018]防御网络

2018-07-15 11:56 351 查看

Description



Solution

考虑每一条边的贡献

对于树边,如果两边各存在一个点,那么有贡献,总贡献就是 \((2^{size}-1)*(2^{n-size}-1)\) 分别对应两边的 \(size\)

对于环上的边,首先最优策略是断掉空隙最大一段, \(DP\) 算贡献

具体来说就是枚举最大空隙长度,每一次转移保证每一段之间的位置之差不超过最大空隙就好了

#include<bits/stdc++.h>
using namespace std;
template<class T>void gi(T &x){
int f;char c;
for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
}
const int N=405,mod=1e9+7,M=1e5+10;
inline int qm(int x,int k){
int sum=1;
while(k){
if(k&1)sum=1ll*sum*x%mod;
x=1ll*x*x%mod;k>>=1;
}
return sum;
}
int dep
,fa
,sz
,a
,cnt=0,b
,f
,ans=0;
inline void solve(int n){
for(int i=1;i<=n;i++)a[i+n]=a[i];
for(int i=1;i<=n-2;i++){
for(int s=1;s<=n;s++){
f[s+i]=a[s+i];
for(int j=s+i+1;j<s+n;j++){
for(int k=1;k<=i;k++)f[j]=(f[j]+f[j-k])%mod;
if(j-i<=n)f[j]=(f[j]+f[j-i-1])%mod;
f[j]=1ll*f[j]*a[j]%mod;
}
ans=(ans+1ll*f[s+n-1]*(n-i-1))%mod;
for(int j=s+i;j<s+n;j++)f[j]=0;
}
}
int t=1;
for(int i=1;i<=n;i++)t=1ll*t*a[i]%mod;
ans=(ans+1ll*t*(n-1))%mod;
cnt=0;
}
int n,m,head
,nxt[M],to[M],num=1;bool vis[M];
inline void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
inline void dfs(int x){
sz[x]=1;
for(int i=head[x],u;i;i=nxt[i]){
if(sz[u=to[i]]){
if(dep[u]>dep[x]){
int v=u,la=0;
while(v!=x){
a[++cnt]=b[sz[v]-sz[la]]-1;
vis[fa[v]]=vis[fa[v]^1]=1;v=to[fa[la=v]^1];
}
a[++cnt]=b[n-sz[la]]-1;vis[i]=vis[i^1]=1;
solve(cnt);
}
continue;
}
fa[u]=i;dep[u]=dep[x]+1;
dfs(u);sz[x]+=sz[u];
}
}
int main(){
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
int x,y;
cin>>n>>m;b[0]=1;
for(int i=1;i<=n;i++)b[i]=b[i-1]*2%mod;
for(int i=1;i<=m;i++){
gi(x);gi(y);
link(x,y);link(y,x);
}
dfs(1);
for(int i=2;i<=num;i+=2)
if(!vis[i]){
x=to[i];y=to[i^1];
if(dep[x]<dep[y])swap(x,y);
ans=(ans+1ll*(b[sz[x]]-1)*(b[n-sz[x]]-1))%mod;
}
ans=1ll*ans*qm(b
,mod-2)%mod;
printf("%d\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: