NC14394. 手铐
描述
给你一个连通无向图,保证每个点最多属于一个简单环,每个点度数最多为3,求这个图有多少“手铐图形个数”
其中“手铐图形个数”,定义为三元组(x,y,S),其中x和y表示图上的两个点,S表示一条x到y的简单路径,而且必须满足:
1.x和y分别在两个不同的简单环上
2.x所在的简单环与路径S的所有交点仅有x,y所在的简单环与路径S的所有交点仅有y。
(x,y,S)与(y,x,S)算同一个手铐
如果你无法理解,可以参考样例。
输入描述
第一行两个数n和m
之后m行,每行两个数x,y表示x和y之间有一条边。
输出描述
输出一个数,表示手铐的个数对19260817取模的结果
示例1
输入:
11 12 1 2 2 3 3 4 4 5 5 1 4 6 6 7 7 8 8 9 9 10 10 11 11 7
输出:
1
说明:
示例2
输入:
14 16 1 2 2 3 3 4 4 1 3 5 5 6 6 7 7 8 8 9 9 6 9 13 13 14 13 10 10 11 11 12 12 10
输出:
4
说明:
C++(g++ 7.5.0) 解法, 执行用时: 1332ms, 内存消耗: 191856K, 提交时间: 2023-05-10 23:03:32
#include<bits/stdc++.h> using namespace std; using ll = long long ; const int mod = 19260817; const int N = 4e6+10; int h[N],e[N<<2],ne[N<<2],idx; void add(int a,int b) { e[idx]=b,ne[idx]=h[a],h[a]=idx++; } int n,m; int ins[N],tot,dfn[N],low[N]; int s[N],top; int cnt,bel[N]; int sz[N]; void tarjan(int u,int fa) { dfn[u]=low[u]=++tot; s[++top]=u; ins[u]=true; for(int i=h[u];~i;i=ne[i]) { int j=e[i]; if(j==fa) continue; if(!dfn[j]) { tarjan(j,u); low[u]=min(low[u],low[j]); } else if(ins[j]) low[u]=min(low[u],dfn[j]); } if(dfn[u]==low[u]) { cnt++; while(1) { int x=s[top--]; bel[x]=cnt; sz[cnt]++; ins[x]=false; if(x==u) break; } } } ll dp[N]; ll f[N]; vector<int> edge[N]; void dfs(int u,int fa) { dp[u]=0; f[u]=(sz[u]>1); for(auto x:edge[u]) { if(x==fa) continue; dfs(x,u); dp[u]=(dp[u]+f[x]*f[u]+dp[x])%mod; f[u]=(f[u]+f[x]*(sz[u]>1?2:1))%mod; } } int main() { ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>n>>m; memset(h,-1,sizeof h); for(int i=1;i<=m;i++) { int a,b; cin>>a>>b; add(a,b),add(b,a); } for(int i=1;i<=n;i++) { if(!dfn[i]) { tarjan(i,-1); } } for(int u=1;u<=n;u++) { for(int i=h[u];~i;i=ne[i]) { int j=e[i]; int x=bel[j],y=bel[u]; if(x!=y) edge[x].push_back(y); } } dfs(1,-1); cout<<dp[1]%mod<<endl; }
C++11(clang++ 3.9) 解法, 执行用时: 1736ms, 内存消耗: 133468K, 提交时间: 2020-01-27 00:13:52
#include <iostream> #include <algorithm> #include <cstdio> #include <queue> #define REP(i,a,n) for(int i=a;i<=n;++i) #define pb push_back using namespace std; typedef long long ll; const int N = 1e6+10, P = 0x0125e591; int n,m,ans,cnt,dep[N],fa[N]; int s[N],vis[N],dp[N]; vector<int> g[N],gg[N]; void get(int x, int y) { if (dep[x]<dep[y]) return; s[y]=++cnt,vis[cnt]=1; for (; x!=y; x=fa[x]) s[x]=cnt; } void dfs(int x, int f) { fa[x]=f,dep[x]=dep[f]+1; for (int y:g[x]) if (y!=f) { if (dep[y]) get(x,y); else dfs(y,x); } } void dfs2(int x, int f) { int t = vis[x]+1; dp[x] = vis[x]; for (int y:gg[x]) if (y!=f) { dfs2(y,x); ans = (ans+(ll)dp[x]*dp[y])%P; dp[x] = (dp[x]+t*dp[y])%P; } } int main() { scanf("%d%d",&n,&m); REP(i,1,m) { int u, v; scanf("%d%d",&u,&v); g[u].pb(v),g[v].pb(u); } dfs(1,0); REP(i,1,n) if (!s[i]) s[i]=++cnt; REP(i,1,n) for (int j:g[i]) { int u=s[i],v=s[j]; if (u!=v) gg[u].pb(v); } dfs2(1,0); if (ans<0) ans += P; printf("%d\n", ans); }