题面说了那么多,其实就一句话:一棵有不超过十条非树边的树,选一个节点就不能选与之相连的节点,求选的方案数
如果没有非树边,就是个sb树形dp
有非树边呢?可以暴力枚举选不选非树边的端点,然后每一种情况树形dp一次
复杂度爆炸
因为非树边很少,所以这不是明摆着用虚树吗
预处理出虚树上每个节点对其父亲的贡献,然后就可以爆搜了
upd:
刚刚把另外一篇HNOI的题解贴过来(因为不想找传送门),然后忘了改传送门,链到了寻宝游戏去,交题的时候re了无数次。。。
Code:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=2e5+5,mod=998244353;
inline int ad(const int &a){return a>=mod?a-mod:a;}
int f[N][2],ff[N][2],l[N],r[N],top,ref[N];
int dfn[N],low[N],tt,s[N];
int head[N],vis[N<<1],nxt[N<<1],tot=0;
int val[N];
int head2[N],vis2[N],nxt2[N];
struct node{
int x,y;
node(){x=0,y=0;}
node(int _x,int _y):x(_x),y(_y){}
inline node operator+(const node &a){return node(x+a.x,y+a.y);}
inline node operator*(const int &a){return node(1ll*x*a%mod,1ll*y*a%mod);}
}w[50],v[50],k[N][2];
inline void add(int u,int v){
vis[++tot]=v,nxt[tot]=head[u],head[u]=tot;
vis[++tot]=u,nxt[tot]=head[v],head[v]=tot;
}
void dfs(int u,int fa=0){
dfn[u]=++tt;
for(int i=head[u];i;i=nxt[i])
if(vis[i]!=fa){
if(!dfn[vis[i]])dfs(vis[i],u),s[u]+=s[vis[i]];
else if(dfn[u]<dfn[vis[i]])l[++top]=u,r[top]=vis[i],ref[u]=1;
else ref[u]=1;
}
ref[u]|=s[u]>=2;s[u]=ref[u]||s[u];
}
inline void Add(int x,int y,node a,node b){vis2[++tot]=y,nxt2[tot]=head2[x],w[tot]=a,v[tot]=b,head2[x]=tot;}
int g[N][2];
int dfs2(int u,int fa=0){
g[u][0]=g[u][1]=1;val[u]=1;int pos=0,w;
for(int i=head[u];i;i=nxt[i])
if(!val[vis[i]]){
int v=vis[i];w=dfs2(v);
if(!w) g[u][1]=1ll*g[u][1]*g[v][0]%mod,g[u][0]=1ll*g[u][0]*(g[v][1]+g[v][0])%mod;
else if(ref[u])Add(u,w,k[v][0]+k[v][1],k[v][0]);
else k[u][1]=k[v][0],k[u][0]=k[v][1]+k[v][0],pos=w;
}
if(ref[u])k[u][0]=node(1,0),k[u][1]=node(0,1),pos=u;
else k[u][0]=k[u][0]*g[u][0],k[u][1]=k[u][1]*g[u][1];
return pos;
}
void dp(int u){
f[u][0]=ff[u][1]?0:g[u][0];
f[u][1]=ff[u][0]?0:g[u][1];
for(int i=head2[u];i;i=nxt2[i]){
int y=vis2[i];dp(y);int p=f[y][0],q=f[y][1];
f[u][1]=1ll*f[u][1]*(1ll*v[i].x*p%mod+1ll*v[i].y*q%mod)%mod;
f[u][0]=1ll*f[u][0]*(1ll*w[i].x*p%mod+1ll*w[i].y*q%mod)%mod;
}
}
int main(){
int n=read(),m=read();
for(int i=1;i<=m;i++) add(read(),read());tot=0;
dfs(1);ref[1]=1;dfs2(1);
int lim=1<<top,ans=0;
for(int i=0;i<lim;i++){
for(int j=0;j<top;j++){
if(i>>j&1)ff[l[j+1]][1]=ff[r[j+1]][0]=1;
else ff[l[j+1]][0]=1;
}
dp(1);ans=ad(ans+ad(f[1][1]+f[1][0]));
for(int j=0;j<top;j++){
if(i>>j&1)ff[l[j+1]][1]=ff[r[j+1]][0]=0;
else ff[l[j+1]][0]=0;
}
}
cout<<ans<<"\n";
return 0;
}