CF711D

题意

n 个点和 n 条边,第 i 条边从 i 连到 ai。每条边需要指定一个方向(无向边变为有向边)。问有多少种指定方向的方案使得图中不出现环。

题解

n 个点和 n 条边。

所以是基环树

先只考虑单棵基环树的情况。

使得图中不出现环。

基环树环外的边对题目没有影响,既不会影响当前的环,也不会增加新的环。

如果基环树的环上的任意一条边与其他的边的方向不同,就不会产生环。

所以在所有的方案中,只有环上边的方向全部相同的情况是会产生环的。

假设环上边的条数为 m,那么此时的产生环的方案数就是 2×2nm 种,不产生环的方案数就是 (2m+2)×2nm 种。

因为题目不保证图联通,所以考虑基环树森林的情况。

所以对于基环树森林中的每一棵基环树,找出其中的环,都像上面那样计算,将结果相加就是答案。

所以最终的答案是: 2nm(2m2)

代码:

#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;
}
posted @   AIskeleton  阅读(24)  评论(0编辑  收藏  举报
编辑推荐:
· 从 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)
点击右上角即可分享
微信分享提示