BZOJ4455 ZJOI2016小星星(容斥原理+树形dp)

  相当于给树上的每个点分配一个编号使父亲和儿子间都有连边。

  于是可以考虑树形dp:设f[i][j][k]为i号点的编号为j,其子树中编号集合为k的方案数。转移显然。然而复杂度3n·n3左右,具体我也不知道是多少,但肯定跑不过。

  如果状态有集合的话不管怎样底数都是3了,考虑能不能变成2。完全不能可以想到容斥。

  于是在dp中去掉k这一维。那么dp变成n3的。但是dp显然会有问题,即会出现不同的点取了相同编号的情况。这也可以看做是有编号未被选择。

  那么就可以容斥了。先算出编号在全集中选择的答案,然后减去在全集去掉一个编号所得子集中选择的答案,再加上在全集去掉两个编号所得子集中选择的答案……通过组合数计算子集被计入的次数容易验证其正确性。

  枚举子集然后dp,复杂度就是O(2n·n3)了。注意卡常。

 

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 18
#define ll long long 
int n,m,a[N][N],stk[N],p[N],t;
ll f[N][N],ans=0;
struct data{int to,nxt;
}edge[N<<1];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void dp(int k,int from,int s)
{
    memset(f[k],0,sizeof(f[k]));
    for (int x=1;x<=s;x++) 
    f[k][stk[x]]=1;
    for (int i=p[k];i;i=edge[i].nxt)
    if (edge[i].to!=from)
    {
        dp(edge[i].to,k,s);
        for (int x=1;x<=s;x++)
        {
            ll sum=0;
            for (int y=1;y<=s;y++)
            if (a[stk[x]][stk[y]]) sum+=f[edge[i].to][stk[y]];
            f[k][stk[x]]=f[k][stk[x]]*sum;
        }
    }
}
void dfs(int k,int s)
{
    if (k>n) 
    {
        dp(1,1,s);
        ll sum=0;
        for (int i=1;i<=n;i++) sum+=f[1][i];
        if (n-s&1) ans-=sum;else ans+=sum;
        return;
    }
    stk[s+1]=k;dfs(k+1,s+1);
    dfs(k+1,s);
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj4455.in","r",stdin);
    freopen("bzoj4455.out","w",stdout);
    const char LL[]="%I64d";
#else
    const char LL[]="%lld";
#endif
    n=read(),m=read();
    while (m--)
    {
        int x=read(),y=read();
        a[x][y]=a[y][x]=1;
    }
    for (int i=1;i<n;i++)
    {
        int x=read(),y=read();
        addedge(x,y),addedge(y,x);
    }
    dfs(1,0);
    cout<<ans;
    return 0;
}

 

posted @ 2018-08-12 14:39  Gloid  阅读(163)  评论(0编辑  收藏  举报