LOJ 2547 「JSOI2018」防御网络——思路+环DP
题目:https://loj.ac/problem/2547
一条树边 cr->v 会被计算 ( n-siz[v] ) * siz[v] 次。一条环边会被计算几次呢?于是去写了斯坦纳树。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
using namespace std;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
int Mx(int a,int b){return a>b?a:b;}
int Mn(int a,int b){return a<b?a:b;}
const int mod=1e9+;
int upt(int x){while(x>=mod)x-=mod;while(x<)x+=mod;return x;}
int pw(int x,int k)
{int ret=;while(k){if(k&)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=;}return ret;} int n,m;
namespace S1{
const int N=,M=(<<)+;
int hd[N],xnt,to[N<<],nxt[N<<];
int bin[N],dp[N][M],dis[N][N]; bool vis[N];
queue<int> q;
void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
void init()
{
for(int i=;i<=n;i++)
{
memset(vis,,sizeof vis);
q.push(i); vis[i]=;
while(q.size())
{
int k=q.front(); q.pop();
for(int i=hd[k],v;i;i=nxt[i])
if(!vis[v=to[i]])
{ vis[v]=;dis[i][v]=dis[i][k]+;q.push(v);}
}
}
bin[]=;for(int i=;i<=n;i++)bin[i]=bin[i-]<<;
}
void solve()
{
for(int i=,u,v;i<=m;i++)
u=rdn(),v=rdn(),add(u,v),add(v,u);
init();
memset(dp,0x3f,sizeof dp);
for(int i=;i<=n;i++)dp[i][bin[i-]]=;
int ans=;
for(int s=;s<bin[n];s++)
{
for(int i=;i<=n;i++)
for(int t=(s-)&s;t;t=(t-)&s)
dp[i][s]=Mn(dp[i][s],dp[i][t]+dp[i][s^t]);
for(int i=;i<=n;i++)q.push(i),vis[i]=;
while(q.size())
{
int k=q.front(); q.pop(); vis[k]=;
for(int i=hd[k],v;i;i=nxt[i])
if(dp[v=to[i]][s]>dp[k][s]+)
{
dp[v][s]=dp[k][s]+;
if(!vis[v])q.push(v),vis[v]=;
}
}
int mn=dp[][s];
for(int i=;i<=n;i++)mn=Mn(mn,dp[i][s]);
ans=upt(ans+mn);
}
ans=(ll)ans*pw(bin[n],mod-)%mod;
printf("%d\n",ans);
}
}
int main()
{
n=rdn();m=rdn();
if(n<=){S1::solve();return ;}
return ;
}
不应从每条环边的角度考虑,而要从每个环的角度考虑。思维还是不足。
想算一个环上有 len 条边被选的方案。
记一个“环外子树(含自己这点)中有点被选的环上点” 为 “被选的点” 。
首先考虑如果有一个选点方案,这个环会被怎么选边。为了把点都连通,被选的点两两之间应该连通。
所以环上没被选的边一定是最远的两个相邻的被选的点之间的部分。
想求一个环 “最远相邻被选点的间隔为 len ” 的方案。注意到 “最远相邻被选点的间隔 <=len ”的方案容易 DP 。
断环成链,dp[ i ][ j ] 表示 i 点和 j 点要选,[ i , j ] 之间被选点间隔 <=len 的方案。则 \( dp[i][j]=f[j]*\sum\limits_{k=j-len}^{j-1}dp[i][k] \) ,其中 \( f[j] \) 是选 j 点的方案,即 ( 2环外子树大小 -1 ) 。
前缀和优化即可。对于一个 len ,合法的 dp[ i ][ j ] 应该满足 (cnt - j) + i <=len (cnt 是环点个数)。把这些加到 g[ len ] 上,用 (cnt-len) * (g[ len ] - g[ len-1 ]) 贡献答案即可。
求环外子树大小要小心。注意清空数组。注意分辨不同的环。可以给环最浅的点打标记,特殊求该点的环外子树大小。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int Mx(int a,int b){return a>b?a:b;}
int Mn(int a,int b){return a<b?a:b;}
const int N=,M=N<<,mod=1e9+;
int upt(int x){while(x>=mod)x-=mod;while(x<)x+=mod;return x;}
int pw(int x,int k)
{int ret=;while(k){if(k&)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=;}return ret;} int n,m,hd[N],xnt,to[M],nxt[M],spe[N];
int dp[N],pr[N],f[N],g[N],siz[N],ans,bin[N];
int tim,dfn[N],low[N],sta[N],top,cnt,col[N],qnt,q[N];
bool vis[N],ins[N];
void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
void tarjan(int cr,int fa)
{
dfn[cr]=low[cr]=++tim; sta[++top]=cr; ins[cr]=;
siz[cr]=;
for(int i=hd[cr],v;i;i=nxt[i])
if((v=to[i])!=fa)
{
if(!dfn[v])
{tarjan(v,cr);low[cr]=Mn(low[cr],low[v]);siz[cr]+=siz[v];}
else if(ins[v])low[cr]=Mn(low[cr],dfn[v]);
}
if(dfn[cr]==low[cr])
{
if(sta[top]==cr){ins[cr]=;top--;return;}
cnt++;
do{int v=sta[top];ins[v]=;col[v]=cnt;}while(sta[top--]!=cr);
spe[cr]=fa;//fa can be 0 but no influence
}
}
void dfsx(int cr)
{
q[++qnt]=cr; vis[cr]=; int id=qnt;
for(int i=hd[cr],v;i;i=nxt[i])
if(!vis[v=to[i]]&&col[v]==col[cr])dfsx(v);//col==
else if(col[v]!=col[cr]&&v!=spe[cr])//include !col
f[id]+=siz[v];//col!= not !col//v!=spe[cr]
if(spe[cr])
f[id]+=n-siz[cr];//+= not =//n-siz[cr] not spe-siz[cr]
f[id]++;
}
void solve(int cr)
{
for(int i=;i<=qnt;i++)f[i]=; qnt=;//f[i]=0//qnt=0
dfsx(cr);
for(int len=;len<=qnt;len++)
{
g[len]=;
for(int i=;i<=len;i++)
{
dp[i]=bin[f[i]]; pr[i]=dp[i]; pr[i-]=;
int lm=qnt-len+i;
if(i>=lm)g[len]=upt(g[len]+dp[i]);
for(int j=i+;j<=qnt;j++)
{
dp[j]=(ll)upt(pr[j-]-pr[Mx(i,j-len)-])*bin[f[j]]%mod;
pr[j]=upt(pr[j-]+dp[j]);
if(j>=lm)g[len]=upt(g[len]+dp[j]);
}
}
}
for(int len=;len<qnt;len++)
ans=(ans+(ll)(qnt-len)*upt(g[len]-g[len-]))%mod;
}
void dfs(int cr)
{
if(col[cr]&&!vis[cr])solve(cr); ins[cr]=;//not use vis again
for(int i=hd[cr],v;i;i=nxt[i])
if(!ins[v=to[i]])
{
if(col[cr]!=col[v]||!col[cr])
//col!= not !col||!col//also !col
ans=(ans+(ll)bin[siz[v]]*bin[n-siz[v]])%mod;
dfs(v);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=,u,v;i<=m;i++)
scanf("%d%d",&u,&v),add(u,v),add(v,u);
bin[]=;for(int i=;i<=n;i++)bin[i]=upt(bin[i-]<<);
for(int i=;i<=n;i++)bin[i]=upt(bin[i]-);//
tarjan(,); dfs();
ans=(ll)ans*pw(bin[n]+,mod-)%mod;
printf("%d\n",ans);
return ;
}
LOJ 2547 「JSOI2018」防御网络——思路+环DP的更多相关文章
- 【LOJ】 #2547. 「JSOI2018」防御网络
题解 如果只是一棵树的话,那么就枚举每条边,分成两部分大小为\(a\)和\(b\) 那么这条边被统计的方案数是\((2^a - 1)(2^b - 1)\) 如果是一个环的话,我们枚举环上至少有\(N ...
- LOJ #2547 Luogu P4517「JSOI2018」防御网络
好像也没那么难写 LOJ #2547 Luogu P4517 题意 在一棵点仙人掌中等概率选择一个点集 求选出点集的斯坦纳树大小的期望 定义点仙人掌为不存在一个点在多个简单环中的连通图 斯坦纳树为在原 ...
- LOJ 2550 「JSOI2018」机器人——找规律+DP
题目:https://loj.ac/problem/2550 只会写20分的搜索…… #include<cstdio> #include<cstring> #include&l ...
- LOJ 2548 「JSOI2018」绝地反击 ——二分图匹配+网络流手动退流
题目:https://loj.ac/problem/2548 如果知道正多边形的顶点,就是二分答案.二分图匹配.于是写了个暴力枚举多边形顶点的,还很愚蠢地把第一个顶点枚举到 2*pi ,其实只要 \( ...
- LOJ 2551 「JSOI2018」列队——主席树+二分
题目:https://loj.ac/problem/2551 答案是排序后依次走到 K ~ K+r-l . 想维护一个区间排序后的结果,使得可以在上面二分.求和:二分可以知道贡献是正还是负. 于是想用 ...
- LOJ 2546 「JSOI2018」潜入行动——树形DP
题目:https://loj.ac/problem/2546 dp[ i ][ j ][ 0/1 ][ 0/1 ] 表示 i 子树,用 j 个点,是否用 i , i 是否被覆盖. 注意 s1<= ...
- LOJ 3093 「BJOI2019」光线——数学+思路
题目:https://loj.ac/problem/3093 考虑经过种种反射,最终射下去的光线总和.往下的光线就是这个总和 * a[ i ] . 比如只有两层的话,设射到第二层的光线是 lst ,那 ...
- LOJ 2541 「PKUWC2018」猎人杀——思路+概率+容斥+分治
题目:https://loj.ac/problem/2541 看了题解才会……有三点很巧妙. 1.分母如果变动,就很不好.所以考虑把操作改成 “已经选过的人仍然按 \( w_i \) 的概率被选,但是 ...
- LOJ 3089 「BJOI2019」奥术神杖——AC自动机DP+0/1分数规划
题目:https://loj.ac/problem/3089 没想到把根号之类的求对数变成算数平均值.写了个只能得15分的暴力. #include<cstdio> #include< ...
随机推荐
- listener介绍
当Web 应用在Web 容器中运行时, Web 应用内部会不断地发生各种事件: 如Web 应用被启动.Web 应用被停止,用户session 开始.用户session 结束.用户请求到达等, 通常来说 ...
- Oracle数据库各种名字的区别
数据库名(DB_NAME).数据库实例名(INSTANCE_NAME).操作系统环境变量(ORACLE_SID).数据库服务名(SERVICE_NAME).数据库域名(DB_DOMAIN)以及全局数据 ...
- tensorFlow入门实践(三)实现lenet5(代码结构优化)
这两周我学习了北京大学曹建老师的TensorFlow笔记课程,认为老师讲的很不错的,很适合于想要在短期内上手完成一个相关项目的同学,课程在b站和MOOC平台都可以找到. 在卷积神经网络一节,课程以le ...
- C++实验:时间和日期类
描述 用C++实现日期类CDate和时间类CTime,并在次基础上利用多继承实现日期时间类CDateTime,使其能输出样例信息. 主函数里的代码已经给出,请补充完整,提交时请勿包含已经给出的代码. ...
- Python之必备函数
1. lambda 表达式 匿名函数(ANONYMOUS FUNCTION)是指一类无需定义标识符(函数名)的函数.通俗来讲,就是它可以让我们的函数,可以不需要函数名. 正常情况下,我们定义一个函数, ...
- 微信小程序 数据库指引 前端操纵数据库失败
把注释解开后,点击添加显示失败了 看了下注解,发现是数据库权限问题, 修改一下成第一个,然后点击又失败了,多点击几下,就会成功! 哦 别忘了时刻 ctrl +s 保存,如果你习惯了idea 自动保存的 ...
- IDEA 自动生成Hibernate实体类和Mapping文件
一.新建工程Demo(如果选的时候勾选了hibernate,IDEA会自动下载Hibernate包,不需要手动导入) 二.导入相关包 Mysql && Hibernate 三.添加Hi ...
- 台达VFD-B变频器调试
一.变频器上电调试 变频器安装完成后,断开变频器的输出,在没通电前先使用数字表的二极管档对变频器的输入输出进行测量,确保无短路情况,然后接通变频器工作电源,(注意变频器标定的工作电源电压与外部输入电压 ...
- spring boot 项目部署在阿里云上
装jdk, 然后 nohup java -jar xxxx.jar> system.log 2>&1 & lsof -i:9999 kill -9 1234
- Sublime Text 3 package control 解决 "There are no packages available for installation" 错误
造成这个错误的原因估计是因为由于packagecontrol.io无法访问,所以导致无法读取“https://packagecontrol.io/channel_v3.json”文件的原因. 解决方法 ...