P8867 [NOIP2022] 建造军营
缩点#
首先考虑对于一个边双内的边是可以任意看守或者不看守的,所以可以缩点,这样缩完点的图就成了一棵树。
对于缩完点后的每一个边双,我们设
那么只考虑一个边双的情况的话,边能任选的方案数就是
状态#
设
但是涵盖情况太多,考虑增加限制。
设
同时强制除
转移#
令
因为上面状态里说了强制除了子树内有军营以外,其他点都没有军营,所以是用
对于
然后考虑如何转移。
对于
对于
code#
/*
* @Author: Aisaka_Taiga
* @Date: 2023-10-27 9:06:57
* @LastEditTime: 2023-10-27 11:14:52
* @LastEditors: Aisaka_Taiga
* @FilePath: \Desktop\P8867.cpp
* The heart is higher than the sky, and life is thinner than paper.
*/
#include <bits/stdc++.h>
#define int long long
#define P 1000000007
#define N 1000100
using namespace std;
inline int read()
{
int x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){if(c == '-') f = -1; c = getchar();}
while(c <= '9' && c >= '0') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return x * f;
}
int n, m, head[N << 1], cnt, E[N], sd[N], dfn[N], vis[N], stk[N], top, low[N], tim, scc, siz[N], ans, s[N], f[N][2];
struct node{int v, next;}e[N << 1];
vector<int> g[N];
inline void add(int u, int v){e[++ cnt] = (node){v, head[u]}; head[u] = cnt;}
inline void tarjan(int u, int fa)
{
dfn[u] = low[u] = ++ tim;
stk[++ top] = u;
vis[u] = 1;
for(int i = head[u]; i; i = e[i].next)
{
int v = e[i].v;
if(v == fa) continue;
if(!dfn[v]) tarjan(v, u), low[u] = min(low[u], low[v]);
else if(vis[v]) low[u] = min(low[u], dfn[v]);
}
if(dfn[u] == low[u])
{
int y; scc ++;
while(1)
{
y = stk[top --];
vis[y] = 0;
sd[y] = scc;
siz[scc] ++;
if(u == y) break;
}
}
return ;
}
inline int ksm(int u, int v)
{
int res = 1;
while(v)
{
if(v & 1) res = (res * u) % P;
u = (u * u) % P, v >>= 1;
}
return res;
}
inline void dfs(int u, int fa)
{
s[u] = E[u];
for(auto v : g[u])
{
if(v == fa) continue;
dfs(v, u);
s[u] += s[v] + 1;
}
return ;
}
inline void DP(int u, int fa)
{
for(auto v : g[u])
{
if(v == fa) continue;
DP(v, u);
f[u][1] = ((f[u][1] * (f[v][0] * 2 % P + f[v][1]) % P) % P + (f[u][0] * f[v][1]) % P) % P;
f[u][0] = f[u][0] * (f[v][0] * 2 % P) % P;
}
if(u == 1) ans = (ans + f[u][1]) % P;
else ans = (ans + f[u][1] * ksm(2, s[1] - s[u] - 1)) % P;
return ;
}
signed main()
{
n = read(), m = read();
for(int i = 1; i <= m; i ++)
{
int u = read(), v = read();
add(u, v), add(v, u);
}
tarjan(1, 0);
for(int u = 1; u <= n; u ++)
{
for(int i = head[u]; i; i = e[i].next)
{
int v = e[i].v;
if(sd[u] == sd[v]) E[sd[u]] ++;
else g[sd[u]].emplace_back(sd[v]);
}
}
for(int i = 1; i <= scc; i ++)
{
E[i] >>= 1;
f[i][0] = ksm(2, E[i]);
f[i][1] = ksm(2, siz[i] + E[i]) - f[i][0];
}
dfs(1, 0);
DP(1, 0);
// for(int i = 1; i <= n; i ++)
// cout << sd[i] << endl;
cout << ans << endl;
return 0;
}
作者: 北烛青澜
出处:https://www.cnblogs.com/Multitree/articles/17791846.html
本站使用「CC BY 4.0」创作共享协议,转载请在文章明显位置注明作者及出处。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!