过于神仙的比赛

T1 graph

题目大意:

一个无向图 若其的一个子图存在欧拉回路 则答案+=这个子图边数的平方

思路:

对于一个连通图 发现一个奇妙的结论即这个联通块的方案数=$2^{m-n+1}$(n为点数,m为边数

然后对于多个联通块 方案数为$2^{m-n+c}$,c为联通块数量

而答案可以转化为$\sum_{x=1}^{m} \sum_{y=1}^{m} F(x,y)$

其中$ F(x,y)$表示强制选x和y这两条边的答案 可以发现若有桥边则一定无解

所以现在考虑选了两条边后对答案的影响 若联通块数+1 则对答案的贡献为$2^{m-n-1}$ 否则为$2^{m-n-2}$

则这道题变成了在无向图上选两条边对联通块数量的影响 可以参考bzoj 3569

对每个非树边rand一个权值 一个树边的权值为覆盖这条边的所有权值异或和 若两条边异或和为0 则说明选这两条边会使联通块数量+1

最后统计一下答案

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<cstring>
 7 #include<vector>
 8 #include<stack>
 9 #include<queue>
10 #include<map>
11 #define rep(i,s,t) for(register int i=(s),i__end=(t);i<=i__end;++i)
12 #define dwn(i,s,t) for(register int i=(s),i__end=(t);i>=i__end;--i)
13 #define ren for(int i=fst[x];i;i=nxt[i])
14 #define Fill(x,t) memset(x,t,sizeof(x))
15 #define ll long long
16 #define ull unsigned long long
17 #define inf 2139062143
18 #define MAXN 170100
19 #define MOD 998244353
20 using namespace std;
21 inline int read()
22 {
23     int x=0,f=1;char ch=getchar();
24     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
25     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
26     return x*f;
27 }
28 int n,m,N,fst[MAXN],to[MAXN<<1],nxt[MAXN<<1],cnt=1,vis[MAXN][2],dfn;//num为所有非桥边,tot为所有使联通块数量+1的边对 
29 ull val[MAXN],v[MAXN<<1],ans=1,tot,num;
30 map <ull,int> hsh;//记录所有边权相同的边
31 void add(int u,int v) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;}
32 inline ull rnd(){ull res=(rand()^(rand()<<16));res<<=32,res|=(rand()^(rand()<<16));return res;}//优秀的ULL rand 
33 void dfs(int x,int pa)
34 {
35     vis[x][0]=++dfn;ren if(i!=(pa^1))
36     {
37         if(!vis[to[i]][0]) dfs(to[i],i);
38         else if(vis[to[i]][0]<vis[x][0])//处理非树边的权值并对这个路径的两端异或该值,在下一次dfs时候可以保证所有路径上的边都被异或(脑补一下 
39             tot++,num++,v[i]=rnd(),val[x]^=v[i],val[to[i]]^=v[i],hsh[v[i]]++;
40     }
41 }
42 void Dfs(int x,int pa)
43 {
44     vis[x][1]=1;ren if(i!=(pa^1)&&!vis[to[i]][1]) {Dfs(to[i],i);val[x]^=val[to[i]];}
45     if(val[x]) {num++;(tot+=(hsh[val[x]]<<1|1))%=MOD;hsh[val[x]]++;}//计算所有边权相同的边对 
46 }
47 int main()
48 {
49     freopen("graph.in","r",stdin);
50     freopen("graph.out","w",stdout);
51     srand(19260817);ll res2;
52     n=read(),m=read(),N=m-n-2,res2=1;int a,b;rep(i,1,m) a=read(),b=read(),add(a,b),add(b,a);
53     rep(i,1,n) if(!vis[i][0]) {dfs(i,-1);Dfs(i,-1);N++;}
54     rep(i,1,N) (ans<<=1)%=MOD;//不影响联通块数量的每个边对的答案
55     rep(i,1,N+1) (res2<<=1)%=MOD;
56     ((num*=num)-=tot)%=MOD;
57     ans=((tot*res2)%MOD+ans*num)%MOD;
58     printf("%lld\n",ans);
59 }
View Code

相关文章:

  • 2021-12-15
  • 2021-06-15
  • 2021-04-02
  • 2021-08-12
  • 2021-12-25
  • 2021-05-27
  • 2021-09-06
  • 2022-01-20
猜你喜欢
  • 2022-01-30
  • 2021-08-19
  • 2022-12-23
  • 2021-04-18
  • 2021-07-06
  • 2021-12-28
相关资源
相似解决方案