bzoj 4455: [Zjoi2016]小星星

链接

http://www.lydsy.com/JudgeOnline/problem.php?id=4455

dp+容斥题意大约是树上的点满足与图上的点一一对应并且图中两两有边,树中也两两有边,求满足条件的方案数

只保证在树在图中两两有边,用dp[i][j]表示树上i点被映射到图中的j点,以i为根的子树方案数,那么方案数可以用dp在$O(n^3)$时间内处理出来

我们把1设为树的根,那么就可以得方案数$\sum\limits_{i=1}^n f(1,i) $

这时的方案数是有重复的,考虑容斥

答案就是ans(n)−ans(n−1)+ans(n−2)−ans(n−3)+ans(n−4).....

我们可以二进制枚举他的子集进行容斥复杂度$O(2^n)$

总复杂度O(2^nn^3)

这道题就做完了

#include<cstdio>
#include<cstring>

const int maxn = 50;
const int MAXN=1e6+10;
inline char nc()
{
    static char buf[MAXN],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXN,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
    char c=nc();int x=0;
    while(c<‘0‘||c>‘9‘)c=nc();
    while(c>=‘0‘&&c<=‘9‘)x=x*10+c-‘0‘,c=nc();
    return x;
}

struct node{
    int v,next;
}edge[maxn*4];
int n,m,num;
int map[maxn*maxn][maxn*maxn],head[maxn];
inline void add_edge(int u,int v) {
    edge[++num].v=v;edge[num].next=head[u];head[u]=num;
}
int node_num=0;
int node[maxn];long long dp[maxn][maxn];
void dfs(int x,int fa) {
    for(int i=1;i<=n;++i)dp[x][node[i]]=1;
    for(int i=head[x];i;i=edge[i].next) {
        int v=edge[i].v;
        if(v==fa)continue;
        dfs(v,x);
        for(int j=1;j<=node_num;++j) {
            long long cnt=0;
            for(int k=1;k<=node_num;++k)
                if(map[node[j]][node[k]])
                    cnt+=dp[v][node[k]];
            dp[x][node[j]]*=cnt;
        }

    }

}
int main() {
    n=read(),m=read();
    long long ans=0;
    for(int a,b,i=1;i<=m;++i) {
        a=read(),b=read();
        map[a][b]=map[b][a]=1;
    }
    for(int a,b,i=1;i<n;++i) {
        a=read(),b=read();
        add_edge(a,b);
        add_edge(b,a);
    }
    for(int i=1;i<(1<<n);++i) {
        node_num=0;
        for(int j=1;j<=n;++j) {
            if((1<<j-1)&i)node[++node_num]=j;
        }
        dfs(1,1);
        long long tot=0;
        for(int j=1;j<=node_num;++j)
            tot+=dp[1][node[j]];
        if((node_num&1)==(n&1))ans+=tot;
        else ans-=tot;
    }
    printf("%lld\n",ans);
    return 0;
}
时间: 2024-08-19 10:09:37

bzoj 4455: [Zjoi2016]小星星的相关文章

4455[Zjoi2016]小星星 容斥+dp

4455: [Zjoi2016]小星星 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 527  Solved: 317[Submit][Status][Discuss] Description 小Y是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品.她有n颗小星星,用m条彩色的细线串了起来,每条细 线连着两颗小星星.有一天她发现,她的饰品被破坏了,很多细线都被拆掉了.这个饰品只剩下了n?1条细线,但 通过这些细线,这颗小星星还是被串在一起,也就是这

【bzoj 4455】小星星(树型DP+容斥原理)

给一个n个点的图和一个n个点的树,求图和树上的点一一对应的方案数.(N<=17)思路:1.在树的结构上进行tree DP,f[i][j]表示树上点 i 对应图上点 j 时,这个点所在子树的方案数.O(n^3).2.我们可以发现如果按这个定义进行DP,“一一对应”的关系挺难保证.若枚举出全排列得到对应关系,这样就C(n,n)=n! 只能拿到暴力分:那么我们就不限制“一一对应”而改为“一对多”的关系进行tree DP,利用容斥原理达到O(2^n)的复杂度.(P.S.至于为什么用容斥原理我也不清楚,待

4455: [Zjoi2016]小星星|状压DP|容斥原理

OrzSDOIR1ak的晨神 能够考虑状压DP枚举子集,求出仅仅保证连通性不保证一一相应的状态下的方案数,然后容斥一下就是终于的答案 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<vector> #include<cmath> #include<queue>

[ZJOI2016]小星星&amp;[SHOI2016]黑暗前的幻想乡(容斥)

这两道题思路比较像,所以把他们放到一块. [ZJOI2016]小星星 题目描述 小Y是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品.她有n颗小星星,用m条彩色的细线串了起来,每条细线连着两颗小星星. 有一天她发现,她的饰品被破坏了,很多细线都被拆掉了.这个饰品只剩下了n-1条细线,但通过这些细线,这颗小星星还是被串在一起,也就是这些小星星通过这些细线形成了树.小Y找到了这个饰品的设计图纸,她想知道现在饰品中的小星星对应着原来图纸上的哪些小星星.如果现在饰品中两颗小星星有细线相连,那么要求对应的

【BZOJ 4455】 [Zjoi2016]小星星 容斥计数

dalao教导我们,看到计数想容斥……卡常策略:枚举顺序.除去无效状态.(树结构) #include <cstdio> #include <cstring> #include <algorithm> typedef long long LL; const int N=20; LL f[N][N]; int n,m,d[N][N],full; bool yeah[N]; int st[N],cnt; struct V{ int to,next; }c[N<<1

【BZOJ 4455】【UOJ #185】【ZJOI 2016】小星星

http://www.lydsy.com/JudgeOnline/problem.php?id=4455 http://uoj.ac/problem/185 有一个$O(n^n)$的暴力,放宽限制可以转化成$O(2^n)$的容斥,容斥每一层统计用$O(n^3)$的dp来统计.时间复杂度$O(n^3 2^n)$. 卡常!存图用邻接表!减小非递归函数的使用,尽量写到主函数里! 最后终于卡过了QwQ #include<cstdio> #include<cstring> #include&

[ZJOI2016]小星星

题目描述 小Y是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品.她有n颗小星星,用m条彩色的细线串了起来,每条细线连着两颗小星星. 有一天她发现,她的饰品被破坏了,很多细线都被拆掉了.这个饰品只剩下了n?1条细线,但通过这些细线,这颗小星星还是被串在一起,也就是这些小星星通过这些细线形成了树.小Y找到了这个饰品的设计图纸,她想知道现在饰品中的小星星对应着原来图纸上的哪些小星星.如果现在饰品中两颗小星星有细线相连,那么要求对应的小星星原来的图纸上也有细线相连.小Y想知道有多少种可能的对应方式. 只

BZOJ4455: [Zjoi2016]小星星

Description 小Y是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品.她有n颗小星星,用m条彩色的细线串了起来,每条细 线连着两颗小星星.有一天她发现,她的饰品被破坏了,很多细线都被拆掉了.这个饰品只剩下了n?1条细线,但 通过这些细线,这颗小星星还是被串在一起,也就是这些小星星通过这些细线形成了树.小Y找到了这个饰品的设 计图纸,她想知道现在饰品中的小星星对应着原来图纸上的哪些小星星.如果现在饰品中两颗小星星有细线相连, 那么要求对应的小星星原来的图纸上也有细线相连.小Y想知道有多少种

bzoj 4455

树的点到图的点是双射 枚举哪些点可以映射到 然后dp容斥 复杂度 $2^n*n^3$ #include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=(a),i##_end=(b);i<=i##_end;++i) #define For(i,a,b) for(int i=(a),i##_end=(b);i<i##_end;++i) #define per(i,a,b) for(int i=(b),i