P8867 [NOIP2022] 建造军营

只有B国袭破坏的道路是无向图的割边时,这张图才会变得不连通,所以我们进行边双缩点,最终形成一棵树,不妨令根节点为\(1\)。

记\(E[u]\)为缩点后的\(u\)包含多少条原图上的边,\(V[u]\)为\(u\)包含多少个原图上的点,并定义\(s[u]\)表示子树\(u\)中的边数。

那么点\(u\)不建造军营的选择是\(2^{E[u]}\),建造军营的选择是\((2^{V[u]}-1)\times 2^{E[u]}\)。

我们设\(f[u][i=0/1]\)表示子树\(u\)选择军营的状态为\(i\)(\(i=0\)表示不选,\(i=1\)表示至少选\(1\)个)的答案。规定子树\(u\)外不建军营,也不选边。

我们思考答案如何统计。

  • 对于\(u\ne 1\),有\(ans\leftarrow ans+f[u][1]\times 2^{s[1]-s[u]-1}\)。

    \(s[1]-s[u]\)是子树\(u\)之外的边数,这里减去的一个\(1\)是\(u\)到\(fa[u]\)的边,我们之所以不统计是为了不重复,下面会说到。
  • 对于\(u=1\),有\(ans\leftarrow ans+f[u][1]\)。

之所以这样设计状态并统计答案是为了不重不漏。我们发现,如果每个答案都在它所建造的所有军营的LCA处进行统计,就可以做到不重不漏。此处我们在定义处限制“不能有军营建在子树外”,统计处限制“\(u\)到\(fa[u]\)的边不选”,其实就是保证了这个条件。


接下来考虑状态转移。

  • 对于\(f[u][0]\),有转移\(f[u][0]=\prod\limits_{\forall v,fa[v]=u}2\times f[v][0]\)。

    \(u\)到\(v\)的边可选可不选,所以要\(\times 2\)。

  • 对于\(f[u][1]\),考虑每新增一个子节点\(v\)对它的贡献。

    • 如果\(v\)之前都没有建造过军营,那么\(v\)点必须建造军营。

      所以有\(f[u][1]\leftarrow f[u][1]+f[u][0]\times f[v][1]\)。

      注意此处的\(f[u][0]\)是\(v\)之前的答案。
    • 如果\(v\)之前已经建造过军营了,那么\(v\)建不建无所谓。且如果\(v\)不建,那么和\(u\)连不连边都可以。

      所以有\(f[u][1]\leftarrow f[u][1]\times (2f[v][0]+f[v][1])\)。

    综上,每遍历到一个子节点\(v\),有\(f[u][1]\leftarrow f[u][1]\times (2f[v][0]+f[v][1])+f[u][0]\times f[v][1]\)。

时间复杂度\(O(n\log (n+m))\),其中\(O(\log (n+m))\)是快速幂。


点击查看代码
#include<bits/stdc++.h>
#define int long long
#define N 500010
#define mod 1000000007
using namespace std;
int n,m,dfn[N],low[N],tim,st[N],top;
int num[N],V[N],E[N],cnt,s[N],f[N][2],ans;
bitset<N> in;
vector<int> G[N],Ga[N];
void tarjan(int u,int fa){
dfn[u]=low[u]=++tim,in[st[++top]=u]=1;
for(int i:G[u]){
if(i==fa) continue;
if(!dfn[i]) tarjan(i,u),low[u]=min(low[u],low[i]);
else if(in[i]) low[u]=min(low[u],dfn[i]);
}
if(dfn[u]==low[u]){
cnt++;
int x;
do in[x=st[top--]]=0,num[x]=cnt,V[cnt]++;
while(x!=u);
}
}
int qpow(int a,int b){
int ans=1;
while(b){
if(b&1) ans=ans*a%mod;
a=a*a%mod,b>>=1;
}
return ans;
}
void dfs(int u,int fa){
s[u]=E[u];
for(int i:Ga[u]) if(i!=fa) dfs(i,u),s[u]+=s[i]+1;
}
void dp(int u,int fa){
for(int i:Ga[u]){
if(i==fa) continue;
dp(i,u);
f[u][1]=(f[u][1]*(((f[i][0]<<1)+f[i][1])%mod)%mod+f[u][0]*f[i][1]%mod)%mod;
f[u][0]=f[u][0]*((f[i][0]<<1)%mod)%mod;
}
if(u==1) ans=(ans+f[u][1])%mod;
else ans=(ans+f[u][1]*qpow(2,s[1]-s[u]-1))%mod;
}
signed main(){
cin>>n>>m;
for(int i=1,u,v;i<=m;i++){
cin>>u>>v;
G[u].emplace_back(v);
G[v].emplace_back(u);
}
tarjan(1,0);
for(int i=1;i<=n;i++){
for(int j:G[i]){
if(num[i]!=num[j]) Ga[num[i]].emplace_back(num[j]);
else E[num[i]]++;
}
}
for(int i=1;i<=cnt;i++){
E[i]>>=1;
f[i][0]=qpow(2,E[i]);
f[i][1]=qpow(2,V[i]+E[i])-f[i][0];
}
dfs(1,0),dp(1,0);
cout<<ans<<"\n";
return 0;
}

[题解]P8867 [NOIP2022] 建造军营的更多相关文章

  1. Solution Set - NOIP2022

    种花 枚举 C 或者 F 最左边的那一竖,考虑对于每一个这一竖上的全 \(0\) 区间 \([l,r]\) 求答案. 记每个点向右延伸最多延伸到 \(L_{i,j}\),对于 C 的情况,枚举列 \( ...

  2. bzoj 1600 &amp; Usaco 月赛 2008 建造栅栏 题解

    [原题] 1600: [Usaco2008 Oct]建造栅栏 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 785  Solved: 443 [Subm ...

  3. 模拟3题解 T3建造游乐园

    T3建造游乐园 这题的关键是推式子 i个点中,有g[i]个方案是度为偶数但不一定连通那么就要减去不合法的设已有j个合法,其个数为f[j],剩下i-j个的方案数是g[i-j]选出来一个固定的点在合法的j ...

  4. [NOIP模拟测试3] 建造游乐园 题解(欧拉图性质)

    Orz 出题人石二队爷 我们可以先求出有n个点的联通欧拉图数量,然后使它删或增一条边得到我们要求的方案 也就是让它乘上$C_n^2$ (n个点里选2个点,要么删边要么连边,选择唯一) 那么接下来就是求 ...

  5. HDU 5813 Elegant Construction(优雅建造)

    HDU 5813 Elegant Construction(优雅建造) Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65 ...

  6. BZOJ1600: [Usaco2008 Oct]建造栅栏

    1600: [Usaco2008 Oct]建造栅栏 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 825  Solved: 473[Submit][Sta ...

  7. usaco training 3.4.3 fence9 题解

    Electric Fence题解 Don Piele In this problem, `lattice points' in the plane are points with integer co ...

  8. 2017年浙江理工大学程序设计竞赛校赛 题解&源码(A.水, D. 简单贪心 ,E.数论,I 暴力)

    Problem A: 回文 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 1719  Solved: 528 Description 小王想知道一个字 ...

  9. Contest1592 - 2018-2019赛季多校联合新生训练赛第二场(部分题解)

    Contest1592 - 2018-2019赛季多校联合新生训练赛第二场 D 10248 修建高楼(模拟优化) H 10252 组装玩具(贪心+二分) D 传送门 题干 题目描述 C 市有一条东西走 ...

  10. 题解 P2701 【[USACO5.3]巨大的牛棚Big Barn】

    题面 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚. 他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方. 我们假定,他的农场划分成 N x N 的方格.输入数据中包括有树的 ...

随机推荐

  1. 把PDF转换成指定后缀名的图片

      生活中难免遇到各种文件类型转换的问题,尤其是在办理一些证件的时候.例如,申请居住证积分的时候,把PDF版本的毕业证扫描件转换成jpg或者png等.下面提供一个工具,用于把PDF转换成指定后缀名的图 ...

  2. DrissionPage.errors.WrongURLError 无效的url,也许要加上"http://"?

    DrissionPage是个强大的工具,使用DrissionPage 读取本地html 报了这个错:"DrissionPage.errors.WrongURLError 无效的url,也许要 ...

  3. 【ZooKeeper面试题】从基础到深入

    ZooKeeper面试题:从基础到深入 基础概念 什么是ZooKeeper?它的主要用途是什么? ZooKeeper是一个分布式的.开源的协调服务,用于分布式应用程序 主要用途:配置管理.命名服务.分 ...

  4. Go Channel介绍

    一.简单说明 Channel是Go中的一个核心类型,可以看做是一个管道,通过它并发核心单元就可以发送或者接收数据进行通讯. 1.1 操作符 这里Channel的操作符是箭头<-,箭头的指向就是数 ...

  5. WDA SEARCH step by step

    之前写了不少的东西,其实大多数都是给自己看的,我的习惯是把资料放到网上,用的时候直接看博客. 之前硬盘轻轻摔了一下,几年的资料没了,然后就再也不用硬盘了. 昨天有人突然问我关于WDA的问题,毕竟奇怪, ...

  6. DTMO直播预告丨ChunJun 2022年开源规划&支持异构数据源DDL转换与自动执行

    ​  DTMO DTMO(DTstack Meetup Online)是袋鼠云数栈技术团队2022年的全新开源项目技术分享活动,我们秉承着开源共享的理念,旨在为大家分享大家分享袋鼠云大数据开源项目家族 ...

  7. Golang基础笔记三之数组和切片

    本文首发于公众号:Hunter后端 原文链接:Golang基础笔记三之数组和切片 这一篇笔记介绍 Golang 里的数组和切片,以下是本篇笔记目录: 数组定义和初始化 数组属性和相关操作 切片的创建 ...

  8. [gym103860D]Tree Partition

    D - Tree Partition 考虑将树转换到一个序列上,钦定\(1\)为根节点,\(1\)的父亲为\(0\),在序列上,孩子向父亲连边 然后考虑设\(dp\)状态\(dp[i][j]\)表示前 ...

  9. apche服务器下无后缀文件配置浏览器访问自动下载

    1.在配置最新的IOS app 微信授权登录时 SDK时,碰到一个问题.服务器端需要配置IOS唤起微信APP授权的通用链接地址. 2.关于通用链接 3. 必须将ios的配置文件放入网址根目录下的app ...

  10. C# WInFomr 窗体圆角

    #region 设置窗体圆角 /// <summary> /// 设置窗体圆角 /// </summary> /// <param name="f"& ...