过于神仙的比赛
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 }