[洛谷P8867] [NOIP2022] 建造军营
[NOIP2022] 建造军营
题目描述
A 国与 B 国正在激烈交战中,A 国打算在自己的国土上建造一些军营。
A 国的国土由 \(n\) 座城市组成,\(m\) 条双向道路连接这些城市,使得任意两座城市均可通过道路直接或间接到达。A 国打算选择一座或多座城市(至少一座),并在这些城市上各建造一座军营。
众所周知,军营之间的联络是十分重要的。然而此时 A 国接到情报,B 国将会于不久后袭击 A 国的一条道路,但具体的袭击目标却无从得知。如果 B 国袭击成功,这条道路将被切断,可能会造成 A 国某两个军营无法互相到达,这是 A 国极力避免的。因此 A 国决定派兵看守若干条道路(可以是一条或多条,也可以一条也不看守),A 国有信心保证被派兵看守的道路能够抵御 B 国的袭击而不被切断。
A 国希望制定一个建造军营和看守道路的方案,使得 B 国袭击的无论是 A 国的哪条道路,都不会造成某两座军营无法互相到达。现在,请你帮 A 国计算一下可能的建造军营和看守道路的方案数共有多少。由于方案数可能会很多,你只需要输出其对 \(1,000,000,007\left(10^{9}+7\right)\) 取模的值即可。两个方案被认为是不同的,当且仅当存在至少一 座城市在一个方案中建造了军营而在另一个方案中没有,或者存在至少一条道路在一个 方案中被派兵看守而在另一个方案中没有。
输入格式
第一行包含两个正整数 \(n,m\),分别表示城市的个数和双向道路的数量。
接下来 \(m\) 行,每行包含两个正整数 \(u_{i},v_{i}\),描述一条连接 \(u_{i}\) 和 \(v_{i}\) 的双向道路。保证没有重边和自环。
输出格式
输出一行包含一个整数,表示建造军营和看守道路的方案数对 \(1,000,000,007\left(10^{9}+ 7\right)\) 取模的结果。
样例 #1
样例输入 #1
2 1
1 2
样例输出 #1
5
样例 #2
样例输入 #2
4 4
1 2
2 3
3 1
1 4
样例输出 #2
184
样例 #3
样例输入 #3
见附加文件里的 barrack/barrack3.in
样例输出 #3
见附加文件里的 barrack/barrack3.ans
样例 #4
样例输入 #4
见附加文件里的 barrack/barrack4.in
样例输出 #4
见附加文件里的 barrack/barrack4.ans
提示
样例 1 解释
A 国有两座城市,一条道路连接他们。所有可能的方案如下:
- 在城市 \(1\) 建军营, 不看守这条道路;
- 在城市 \(1\) 建军营, 看守这条道路;
- 在城市 \(2\) 建军营, 不看守这条道路;
- 在城市 \(2\) 建军营, 看守这条道路;
- 在城市 \(1,2\) 建军营, 看守这条道路。
数据规模与约定
对所有数据,保证 \(1 \leq n \leq 5 \times 10^5\),\(n - 1 \leq m \leq 10^6\),\(1 \leq u_i, v_i \leq n\),\(u_i \neq v_i\)。
各测试点的信息如下
| 测试点编号 | $n \leq $ | $m \leq $ | 特殊条件 |
|---|---|---|---|
| \(1 \sim 3\) | \(8\) | \(10\) | 无 |
| \(4 \sim 7\) | \(16\) | \(25\) | 无 |
| \(8 \sim 9\) | \(3000\) | \(5000\) | 无 |
| \(10 \sim 11\) | \(5 \times 10^5\) | \(10^6\) | 特殊性质 \(\mathrm{A}\) |
| \(12 \sim 14\) | \(5 \times 10^5\) | \(10^6\) | \(m = n - 1\) |
| \(15 \sim 16\) | \(5 \times 10^5\) | \(10^6\) | \(m = n\) |
| \(17 \sim 20\) | \(5 \times 10^5\) | \(10^6\) | 无 |
特殊性质 \(\mathrm{A}\):保证 \(m=n-1\) 且第 \(i\) 条道路连接城市 \(i\) 与 \(i+1\)。
试想,如果两个城市在一个边双连通分块里面,那么肯定没有办法通过删除一条边来使这两个城市分隔两地。所以可以考虑边双连通分块。
先把双连通分块缩成一个点,缩完后就是一棵树。这棵树中我们可以选任意个点,任意个边,要求所有点必须被联通的方案数。一看就是树形dp.
定义 \(dp_{i,0}\) 为 \(i\) 的子树中一定有选点,子树外没有选点时的方案数,\(dp_{i,1}\) 为 \(i\) 的子树中一定有选点,子树外有选点的方案数。为什么要控制子树外和子树外呢?因为这会影响到边是否必选的情况。钦定根为1,那么最终答案为 \(dp_{1,0}\)。同时可以发现,如果一棵子树中没点,那么方案数就是当中的边选不选了。
\(dp_{x,1}\) 的转移简单,那就先看他吧。设 \((x,y)\) 有边子树外存在点,那么如果 \(y\) 中有选择点,那么 \((x,y)\) 这条边必选,然后递归到 \(dp_y\) 计算。如果 \(a\) 是所有的子树的方案数,b为所有子树都不选点的方案数。如果 \(x\) 为关键点,方案数为 \(a\)。否则就要在子树中至少选一个点,方案数 \(a-b\)(要减去一个点都不选的)。注意我们上面进行了一个缩点,所以如果某一个点如果要将他选为关键点,那么方案也有 \(2^c\),\(c\) 为这个边双的点的数量。
来看 \(dp_{x,0}\) 的转移,那么此时子 \(x\) 树内必须选点,那要分成子树内只有某一棵子树有点的情况和子树内有多棵子树有点的情况。如果只有一棵子树有点,那么递归到 \(dp_{y,0}\) 计算,否则递归到 \(dp_{y,1}\) 计算。最后注意要 \(dp_{y,1}\) 要减去只选某一棵子树或者没选点的情况。
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int N=5e5+5,M=2e6+5,P=1e9+7;
int n,m,u,v,e_num=1,hd[N],dfn[N],low[N],id[N],h[N],g_num,idx,tme,cnt,sz[N],c[N],pw[M],dp[N][2],ans;
struct edge{
int u,v,nxt,f;
}e[M],g[M];
void add_edge(int u,int v)
{
e[++e_num]=(edge){u,v,hd[u],0};
hd[u]=e_num;
}
void addedge(int u,int v)
{
// printf("%d %d\n",u,v);
g[++g_num]=(edge){u,v,h[u],0};
h[u]=g_num;
}
void tarjan(int x,int y)
{
dfn[x]=low[x]=++idx;
for(int i=hd[x];i;i=e[i].nxt)
{
if(e[i].v!=y)
{
if(!dfn[e[i].v])
{
tarjan(e[i].v,x);
low[x]=min(low[x],low[e[i].v]);
}
else
low[x]=min(low[x],dfn[e[i].v]);
if(low[e[i].v]>dfn[x])
e[i].f=e[i^1].f=1;
}
}
}
void sou(int x,int tme)
{
id[x]=tme,c[tme]++;
for(int i=hd[x];i;i=e[i].nxt)
if(!e[i].f&&!id[e[i].v])
sou(e[i].v,tme);
}
void dfs(int x,int y)
{
sz[x]=1;
int a=1,b=1,d=0,e=0,f=1;
for(int i=h[x];i;i=g[i].nxt)
{
if(g[i].v!=y)
{
dfs(g[i].v,x);
sz[x]+=sz[g[i].v];
}
}
// printf("%d\n",d);
for(int i=h[x];i;i=g[i].nxt)
{
if(g[i].v!=y)
{
a=1LL*a*(pw[sz[g[i].v]]+dp[g[i].v][1])%P;
b=1LL*b*pw[sz[g[i].v]]%P;
(d+=1LL*pw[sz[x]-sz[g[i].v]-1]*dp[g[i].v][1]%P)%=P;
(e+=1LL*pw[sz[x]-sz[g[i].v]]%P*dp[g[i].v][0]%P)%=P;
// f=1LL*f*(pw[sz[g[i].v]]+dp[g[i].v][1]);
}
}
// printf("%d\n",d);
dp[x][1]=(((a-b)+1LL*(pw[c[x]]-1)*a%P)%P+P)%P;
dp[x][0]=(1LL*(pw[c[x]]-1)*a%P+((a-b-d)%P+P)%P+e)%P;
// printf("%d\n",d);
// printf("%d %d %d\n",x,dp[x][0],dp[x][1]);
// printf("%d %d %d %d %d %d %d %d\n",x,dp[x][0],dp[x][1],a,f,b,d,e);
}
int main()
{
// freopen("barrack.in","r",stdin);
// freopen("barrack.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=pw[0]=1;i<=m;i++)
pw[i]=pw[i-1]*2%P;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
add_edge(u,v);
add_edge(v,u);
}
// printf("%d\n",e_num);
for(int i=1;i<=n;i++)
if(!dfn[i])
tarjan(i,0);
for(int i=1;i<=n;i++)
{
if(!id[i])
{
++tme;
sou(i,tme);
}
}
for(int i=2;i<=e_num;i+=2)
{
if(id[e[i].u]==id[e[i].v])
++cnt;
else
{
addedge(id[e[i].u],id[e[i].v]);
addedge(id[e[i].v],id[e[i].u]);
}
}
// printf("%d\n",cnt);
dfs(1,0);
// printf("%llu %llu\n",pw[cnt],dp[1]+pw[tme-1]-1);
// printf("%d\n",pw[cnt]);
// printf("%d\n",cnt);
printf("%d",(1LL*pw[cnt]*dp[1][0]%P));
return 0;
}
[洛谷P8867] [NOIP2022] 建造军营的更多相关文章
- 洛谷 P2701 [USACO5.3]巨大的牛棚Big Barn Label:二维数组前缀和 你够了 这次我用DP
题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N ...
- 洛谷P1519 穿越栅栏 Overfencing
P1519 穿越栅栏 Overfencing 69通过 275提交 题目提供者该用户不存在 标签USACO 难度普及/提高- 提交 讨论 题解 最新讨论 USACO是100分,洛谷是20分 为什么 ...
- BZOJ1015或洛谷1197 [JSOI2008]星球大战
BZOJ原题链接 洛谷原题链接 发现正着想毫无思路,所以我们可以考虑倒着思考,把摧毁变成建造. 这样很容易想到用并查集来维护连通块,问题也变的很简单了. 建原图,先遍历一遍所有边,若某条边的两端点未被 ...
- 洛谷P4312 [COCI 2009] OTOCI / 极地旅行社(link-cut-tree)
题目描述 不久之前,Mirko建立了一个旅行社,名叫“极地之梦”.这家旅行社在北极附近购买了N座冰岛,并且提供观光服务. 当地最受欢迎的当然是帝企鹅了,这些小家伙经常成群结队的游走在各个冰岛之间.Mi ...
- [洛谷P4609] [FJOI2016]建筑师
洛谷题目链接:[FJOI2016]建筑师 题目描述 小 Z 是一个很有名的建筑师,有一天他接到了一个很奇怪的任务:在数轴上建 \(n\) 个建筑,每个建筑的高度是 \(1\) 到 \(n\) 之间的一 ...
- [POI 2008&洛谷P3467]PLA-Postering 题解(单调栈)
[POI 2008&洛谷P3467]PLA-Postering Description Byteburg市东边的建筑都是以旧结构形式建造的:建筑互相紧挨着,之间没有空间.它们共同形成了一条长长 ...
- 洛谷1578:[WC2002]奶牛浴场——题解
https://www.luogu.org/problemnew/show/P1578#sub 由于John建造了牛场围栏,激起了奶牛的愤怒,奶牛的产奶量急剧减少.为了讨好奶牛,John决定在牛场中建 ...
- 洛谷P4198 楼房重建 (分块)
洛谷P4198 楼房重建 题目描述 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题, ...
- 洛谷P1273 有线电视网 (树上分组背包)
洛谷P1273 有线电视网 题目描述 某收费有线电视网计划转播一场重要的足球比赛.他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节 ...
- 「BZOJ1038」「洛谷P2600」「ZJOI2008」瞭望塔 半平面交+贪心
题目链接 BZOJ/洛谷 题目描述 致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安. 我们将H村抽象为一维的轮廓.如下图所示: 我们可以用一条山的上方 ...
随机推荐
- Kali-Linux-配置开发环境
本文主要讲解JDK.SDK.eclipse-adt.android studio.cpu模式TensorFlow 的安装配置.update:2019-08-30 03:31:46 JDK 当前系统jd ...
- kmp的简单应用
Smiling & Weeping ---- 我只为你一个人写过月亮 题目链接:P4824 [USACO15FEB] Censoring S - 洛谷 | 计算机科学教育新生态 (luogu. ...
- 正则表达式快速入门三: python re module + regex 匹配示例
使用 Python 实现不同的正则匹配(从literal character到 其他常见用例) reference python regular expression tutorial 目录 impo ...
- HTML一键打包IPA(苹果IOS应用)工具 网站打包 APP
工具简介 HTML一键打包IPA(苹果应用)工具可以把本地HTML项目或者网站打包为一个苹果应用IPA文件,无需编写任何代码,支持在苹果设备上安装运行. 该软件已经被GDB苹果网页一键打包工具取代,详 ...
- AnyLabeling标定及转化成labelmaskID
一.标定工具 在进行分割任务时,对分割工具进行预研和验证,现在AI辅助标定已经成熟,目标则是利用sam进行辅助标定.调研的三款标定工具情况如下: labelme:可以加载sam,但是在进行辅助标定后, ...
- 一些H5对接微信JSSDK的问题记录
这里给大家分享我在实际生活中总结出来的一些知识,希望对大家有所帮助 一.SDK引入 这里提供两套引入流程,一套是vue2.0及其他h5项目,一套是vue3.0的引入流程 不懂的也可以看我之前的一篇详细 ...
- 万字长文 | 泰康人寿基于 Apache Hudi 构建湖仓一体平台的应用实践
文章贡献者 Authors 技术指导: 泰康人寿 数据架构资深专家工程师 王可 文章作者: 泰康人寿 数据研发工程师 田昕峣 摘要 Abstract 本文详细介绍了泰康人寿基于 Apache Hudi ...
- 爬虫系列——requests
文章目录 一 介绍 二 基于GET请求 三 基于POST请求 四 响应Response 五 高级用法 一 介绍 介绍:使用requests可以模拟浏览器的请求,比起之前用到的urllib,reques ...
- idea修改默认maven配置
idea修改默认maven配置 方法一 (不推荐) 打开project.default.xml文件,在其中加入如下几行配置. 代码如下 保存修改之后新建一个maven项目查看效果 方法二 新增Proj ...
- P4022 [CTSC2012]熟悉的文章 题解
题目链接 简要题意 给定 \(m\) 个模板串和 \(n\) 个匹配串,如果一个字符串是一个模板串的子串且长度不小于 \(L\) 则称其为"熟悉的",对于每个匹配串,求一个最大的 ...