CF711D
题意
有 个点和 条边,第 条边从 连到 。每条边需要指定一个方向(无向边变为有向边)。问有多少种指定方向的方案使得图中不出现环。
题解
个点和 条边。
所以是基环树。
先只考虑单棵基环树的情况。
使得图中不出现环。
基环树环外的边对题目没有影响,既不会影响当前的环,也不会增加新的环。
如果基环树的环上的任意一条边与其他的边的方向不同,就不会产生环。
所以在所有的方案中,只有环上边的方向全部相同的情况是会产生环的。
假设环上边的条数为 ,那么此时的产生环的方案数就是 种,不产生环的方案数就是 种。
因为题目不保证图联通,所以考虑基环树森林的情况。
所以对于基环树森林中的每一棵基环树,找出其中的环,都像上面那样计算,将结果相加就是答案。
所以最终的答案是:
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e5;int n,m=1e9+7,tot,vis[N],si[N],a[N],b[N],ans=1;
struct edge{int v,nt;}e[N<<1];
int fir[N],cnt;
void add(int u,int v){e[++cnt].v=v;e[cnt].nt=fir[u];fir[u]=cnt;}
int k(int a,int b){int s=1;while(b){if(b&1)(s*=a)%=m;(a*=a)%=m;b>>=1;}return s;}
void dfs(int u,int c){
if(vis[u]){b[tot]=max(b[tot],c-si[u]);return;}
si[u]=c;vis[u]=1;a[tot]++;
for(int i=fir[u];i;i=e[i].nt)dfs(e[i].v,c+1);
}signed main(){
std::ios::sync_with_stdio(false);
cin>>n;for(int i=1,x;i<=n;i++) cin>>x,add(i,x),add(x,i);
for(int i=1;i<=n;i++)
if(!vis[i]) tot++,dfs(i,0);
for(int i=1;i<=tot;i++)
ans=(ans*((k(2,a[i])-k(2,a[i]-b[i]+1))%m)%m+m)%m;
cout<<ans<<endl;return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)