一定要记得开LL啊啊啊啊啊啊啊啊啊啊啊
被琛爷d飞了
我只会强行上树包TLE得飞起(f[i][zt]表示当前子树匹配图上的那些点)
但是zt我们可以换成和根匹配的是那些点,然后加一个容斥,枚举子集,树上两点可以选图中同一个点
注意不能树和图同步dfs,这个复杂度是假的。。。
要在dfs里面枚举当前点和那个点匹配,然后再枚举更新
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; struct node { int x,y,next; }a[410];int len,last[20]; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } int mp[20][20]; int n,t[20];LL f[20][20]; bool vis[20]; void dfs(int x) { vis[x]=true; for(int k=last[x];k;k=a[k].next) if(vis[a[k].y]==false)dfs(a[k].y); for(int i=1;i<=t[0];i++) { f[x][t[i]]=1; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(vis[y])continue; LL s=0; for(int j=1;j<=t[0];j++) if(mp[t[i]][t[j]])s+=f[y][t[j]]; f[x][t[i]]*=s; if(f[x][t[i]]==0)break; } } vis[x]=false; } int lowbit(int x){return x&-x;} int one(int zt) { int ret=0; while(zt>0) { ret++; zt-=lowbit(zt); } return ret; } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int m,x,y; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); mp[x][y]=mp[y][x]=true; } len=0;memset(last,0,sizeof(last)); for(int i=1;i<n;i++) { scanf("%d%d",&x,&y); ins(x,y),ins(y,x); } int li=(1<<n)-1; LL ans=0; for(int zt=1;zt<=li;zt++) { t[0]=0; for(int i=1;i<=n;i++) if((1<<i-1)&zt)t[++t[0]]=i; dfs(1); if((n-one(zt))%2==0)for(int i=1;i<=t[0];i++)ans+=f[1][t[i]]; else for(int i=1;i<=t[0];i++)ans-=f[1][t[i]]; } printf("%lld ",ans); return 0; }