首页 > 其他分享 >[NOIP2022] 建造军营

[NOIP2022] 建造军营

时间:2022-12-19 14:55:51浏览次数:44  
标签:10 sz int 样例 建造 军营 NOIP2022 dp

[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;
}

标签:10,sz,int,样例,建造,军营,NOIP2022,dp
From: https://www.cnblogs.com/mekoszc/p/16989845.html

相关文章

  • NOIP2022 游记(by Fy5Fengye)
    Day-x,11.?马上就是联赛了,不紧张是不现实的。每天都是模拟赛,每天都被爆锤……但是只要我没有心,就莫得心态问题!=)Day-7~-1,11.18~11.24联赛前一周。已经很难学进去什么......
  • NOIP2022 游记
    至少应该留下一点记忆。也不能只执着于赛场。隔了大约20天再来写这篇游记,我的记忆果然已经模糊不清了,或许是我刻意遗忘,也可能真的是当时的精神状态不好。DAY-4正好......
  • NOIP2022 题解
    终于有机会补NOIP的题了T1考虑枚举C与F的纵列考虑预处理出每个点最左边和最下边可以延伸到哪之后枚举列,然后对行做类似于扫描线的操作,统计有多少可行的"第一横行"......
  • NOIP2022 总结
    赛时考场T1秒,写调1h(中间拉肚子了。。)先看题。写了234暴力,走人看T2。感觉不是很会。急急急。、大概快2h30min?的时候想到了个做法,写写写。写出来一遍过样例。看看文件......
  • NOIP2022 题解
    T2T3......
  • NOIP2022总结
    拿到题先看T1,发现有点水,一眼秒了,15min直接写完。然后看T1,是一道交互题,以为不难,就开始胡做法,胡了好多假做法,没想清楚就开始写了,弄了2h还没什么进展。中途看了一眼......
  • 建造者模式
     ​​http://blog.51cto.com/craftsman001/1662488​​建造者模式需要四大角色:(1)目标者类Target:有n个属性。不能多变。(2)抽象建造者接口Builder:关联目标类Target,对应n个属性......
  • 创建型:设计模式之建造模式(四)
     没有人买车会只买一个轮胎或者方向盘,大家买的都是一辆包含轮胎、方向盘和发动机等多个部件的完整汽车。如何将这些部件组装成一辆完整的汽车并返回给用户,这是建造者模式需......
  • 故事终章,NOIP2022
    挥之不去的梦魇没有前情提要Day0上午到机房,监督高一做题,因为没有高二和初中。午饭前后打了一会儿CS,被薄纱。午饭尝试了酸菜鱼面,差点吐了,直接倒掉。快下午才睡午觉......
  • [NOIP2022] 比赛
    [NOIP2022]比赛很明显要离线,枚举右端点对于\([L,R]\)中取子区间的最大值求和不是很好维护定义\(f_l\)为当前左端点为\(l\),\(\sum\limits_{r=l}^RAns(l,r)\)\(Query(l......