#10 //I [HNOI/AHOI2018]毒瘤
题解:
80分做法还是听简单的
对于非树边枚举一下端点状态
然而我也不知道为什么就多t了一个点
具体实现上
最暴力的是3^n次 但是我们可以发现对于i不取,j取 i不取,j不取是可以等效成i不取,j没有限制,这样是2^n
或者直接容斥一下搞i取j取 这样C(n,1)+C(n,2)...=2^n一样的吧
100pts应该是虚树处理一下系数吧
代码:
#include <bits/stdc++.h> using namespace std; #define N 300000 #define rg register #define mo 998244353 #define ll long long struct re{ int a,b; }a[N],ts[15]; const int n2=1e7; int head[N],l2,l,v[N],n,m,hash[n2]; ll dp[N][2],ans; bool f[N],ff[N]; inline void arr(int x,int y) { a[++l].a=head[x]; a[l].b=y; head[x]=l; } inline void dfs(int x,int y) { rg int u=head[x]; f[x]=1; while (u) { rg int v=a[u].b; if (u!=y) { if (f[v]) { if (!ff[u]) { ts[++l2].a=a[u].b; ts[l2].b=x; ff[u]=1; ff[u%2?u+1:u-1]=1; } } else dfs(v,u%2?u+1:u-1); } u=a[u].a; } } inline void dfs3(rg int x,rg int y) { rg int u=head[x]; dp[x][0]=1; dp[x][1]=1; if (v[x]==1) dp[x][0]=0; if (v[x]==-1) dp[x][1]=0; while (u) { rg int v=a[u].b; if (u!=y&&!ff[u]) { dfs3(v,u%2?u+1:u-1); dp[x][1]*=dp[v][0]; dp[x][1]%=mo; dp[x][0]*=(dp[v][0]+dp[v][1]); dp[x][0]%=mo; } u=a[u].a; } } const int mo1=9e6+7; inline void dfs2(rg int now) { if (now==0) { memset(dp,0,sizeof(dp)); dfs3(1,0); ans+=dp[1][0]+dp[1][1]; ans%=mo; return; } rg int x=ts[now].a,y=ts[now].b; rg int tmp1=v[x],tmp2=v[y]; if (v[x]!=1&&v[y]!=-1) { v[x]=-1; v[y]=1; dfs2(now-1); v[x]=tmp1; v[y]=tmp2; } if (v[y]!=1) { v[y]=-1; dfs2(now-1); v[y]=tmp2; } } int main() { freopen("noi.in","r",stdin); freopen("noi.out","w",stdout); std::ios::sync_with_stdio(false); cin>>n>>m; int x,y; for (rg int i=1;i<=m;i++) { cin>>x>>y; arr(x,y); arr(y,x); } dfs(1,0); dfs2(l2); cout<<ans<<endl; return 0; }