【bzoj3349】[Zjoi2016]小星星

26 篇文章 0 订阅
1 篇文章 0 订阅

容斥+树形dp

SSf[x][y]xyx

#include <bits/stdc++.h>
#define gc getchar()
#define ll long long
#define N 18
#define M N*N/2
using namespace std;
int n,m,x,y,first[N],First[N],Number,number,q[N],w;
int mp[N][N],fa[N];
ll dp[N][N],Ans;
struct edge
{
    int from,to,next;
    void add(int x,int y)
    {
        from=x,to=y,next=first[x],first[x]=number;
    }
}e[M];
int read()
{
    int x=1;
    char ch;
    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
    int s=ch-'0';
    while (ch=gc,ch<='9'&&ch>='0') s=s*10+ch-'0';
    return s*x;
}
void tree_dp(int x)
{
    for (int i=1;i<=w;i++)
        dp[x][q[i]]=1;
    for (int i=first[x];i;i=e[i].next)
        if (fa[x]!=e[i].to)
        {
            fa[e[i].to]=x;
            tree_dp(e[i].to);
            for (int j=1;j<=w;j++)
            {
                ll sum=0;
                for (int k=1;k<=w;k++)
                    if (mp[q[j]][q[k]])
                        sum+=dp[e[i].to][q[k]];
                dp[x][q[j]]*=sum;
            }
        }
}
int main()
{
    n=read(),m=read();
    for (int i=1;i<=m;i++)
    {
        x=read(),y=read();
        mp[x][y]=mp[y][x]=1;
    }
    for (int i=1;i<n;i++)
    {
        x=read(),y=read();
        e[++number].add(x,y);
        e[++number].add(y,x);
    }
    Ans=0;
    for (int i=1;i<(1<<n);i++)
    {
        memset(dp,0,sizeof(dp));
        w=0;
        for (int k=i,j=1;k;k>>=1,j++)
            if (k&1) q[++w]=j;
        tree_dp(1);
        ll sum=0;
        for (int j=1;j<=w;j++)
            sum+=dp[1][q[j]];
        if ((n&1)==(w&1)) Ans+=sum;
        else Ans-=sum;
    }
    printf("%lld\n",Ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值