博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
洛谷P4517 [JSOI2018]防御网络(dp)
阅读量:6704 次
发布时间:2019-06-25

本文共 3059 字,大约阅读时间需要 10 分钟。

题面

题解

翻译一下题意就是每次选出一些点,要用最少的边把这些点连起来,求期望边数

我也不知道为什么反正总之就是暴力枚举太麻烦了所以我们考虑贡献

如果一条边是割边,那么它会在图里当且仅当两边的联通块中都有点被选,设其中一边的点的个数为\(siz\),那么方案数就是\((2^{siz}-1)(2^{n-siz}-1)\)

然而如果一条边是环边就会变得非常麻烦了……每种方案相当于这个环上有若干个点被标记,要用最少的边数将它们连起来,那么边数就是环的大小减去\(\max(\)两个相邻点之间的边数\()\)

这个不能分开考虑了,我们把整个环给一起考虑

\(dp_{i,j,k}\)表示选择的点中左端点为\(i\),右端点为\(j\),不考虑\(j->n->i\)这条路径的情况下的两两相邻点之间最大值为\(k\)的情况,设环长为\(n\),那么这个就会产生\((n-\max(k,n+i-j))\times dp_{i,j,k}\)的贡献

转移方程为

\[dp_{i,j,k}=(2^{siz_j}-1)\left(\sum_{p=0}^kdp_{i,j-k,p}+\sum_{p=j-k+1}^{j-1}dp_{i,p,k}\right)\]

上面的方程的意思就是,如果\(j\)和前面一个点的长度恰好为\(k\),那么前面最大长度可以任取,否则前面最大长度就必须等于\(k\)

发现转移方程里的两个柿子都可以写成前缀和的形式,那么我们一边计算一边维护前缀和,总的复杂度就是\(O(n^3)\)

//minamoto#include
#define R register#define fp(i,a,b) for(R int i=(a),I=(b)+1;i
I;--i)#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)template
inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}using namespace std;char buf[1<<21],*p1=buf,*p2=buf;inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}int read(){ R int res,f=1;R char ch; while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1); for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0'); return res*f;}const int N=1005,P=1e9+7;inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}int ksm(R int x,R int y){ R int res=1; for(;y;y>>=1,x=mul(x,x))if(y&1)res=mul(res,x); return res;}struct eg{int v,nx,w,f;}e[N<<1];int head[N],tot=1;inline void add_edge(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}int dfn[N],low[N],sz[N],vis[N],sum1[N][N],sum2[N][N],st[N],val[N];int n,m,tim,res,top,tmp,u,v;void tarjan(int u,int fa){ low[u]=dfn[u]=++tim,sz[u]=1; go(u)if(v!=fa){ if(!dfn[v])tarjan(v,u),cmin(low[u],low[v]),sz[u]+=sz[v]; else cmin(low[u],dfn[v]); if(low[v]>dfn[u]){ e[i].f=e[i^1].f=1,res=add(res,mul(ksm(2,sz[v])-1,ksm(2,n-sz[v])-1)); e[i].w=sz[v],e[i^1].w=n-sz[v]; } }}inline int nxt(R int u){go(u)if(!e[i].f&&!vis[v])return v;return 0;}void solve(int p){ top=0;while(p)st[++top]=p,vis[p]=1,p=nxt(p); if(top==1)return; fp(i,1,top)val[i]=1; fp(u,1,top)go(st[u])val[u]+=e[i].w; fp(i,1,top)val[i]=ksm(2,val[i])-1; fp(i,1,top-1){ fp(j,0,top)sum2[i][j]=val[i]; fp(j,i+1,top)fp(k,1,top){ tmp=0; if(j-i>=k){ tmp=mul(val[j],add(sum2[j-k][k],dec(sum1[j-1][k],sum1[j-k][k]))); res=add(res,mul(tmp,top-max(top+i-j,k))); } sum1[j][k]=add(sum1[j-1][k],tmp),sum2[j][k]=add(sum2[j][k-1],tmp); } fp(j,i,top)fp(k,0,top)sum1[j][k]=sum2[j][k]=0; }}int main(){// freopen("testdata.in","r",stdin); n=read(),m=read(); fp(i,1,m)u=read(),v=read(),add_edge(u,v),add_edge(v,u); tarjan(1,0); fp(i,1,n)if(!vis[i])solve(i); printf("%d\n",mul(res,ksm(ksm(2,n),P-2))); return 0;}

转载于:https://www.cnblogs.com/bztMinamoto/p/10512110.html

你可能感兴趣的文章
linux进程
查看>>
rabbitmq routing and binding relation
查看>>
clojure 备忘
查看>>
CentOS7上搭建Maven服务器
查看>>
关于dispatch_semaphore的使用
查看>>
VS2008编译工程缺少glaux库的解决方法
查看>>
Linux Crontab 定时任务 命令详解
查看>>
android APN cmnet切换cmwap
查看>>
Xcode环境变量列表
查看>>
openlava-4.0 安装教程(VMware/centos7)
查看>>
fineui实时监控(增、删、改)+CDC+长连接(一)
查看>>
mysql5.7的半同步复制
查看>>
Apache HttpClient (理解Http Client)
查看>>
Alibaba Sentinel 源码阅读(Part 2 LeapArray)
查看>>
Spring(三)装配Bean:手动装配Bean
查看>>
eclipse 调试时出现!MESSAGE Could not find bundle: or...
查看>>
ERROR Found the synthetic property @routerTransition
查看>>
js如何只获得Element自定义属性(自己手写在标签上的规定属性),不是自定义属性$(obj).attr("xx")...
查看>>
jquery support
查看>>
申奥动画长片名单出炉,动画质量大PK
查看>>