• bzoj4455:[Zjoi2016]小星星


    传送门

    考虑假如不考虑重复映射
    那么显然可以得到一个(O(n^3))的树形dp
    然后考虑如何去掉不合法的情况?
    容斥,考虑每次只能从一个点集(S)里选点(也就是至多(|S|)个点的映射的方案数)
    那么显然就可以枚举点集(S),做树形dp,然后容斥一下就做完了
    总复杂度:(O(2^nn^3))
    代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    void read(int &x){
    	char ch;bool ok;
    	for(ok=0,ch=getchar();!isdigit(ch);ch=getchar())if(ch=='-')ok=1;
    	for(x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());if(ok)x=-x;
    }
    #define rg register
    const int maxn=20;
    int n,m,d[maxn][maxn],dd[maxn][maxn],t[maxn],num,tot;
    long long f[maxn][maxn],ans;
    void dfs(int x,int fa){
    	for(rg int i=1;i<=num;i++)f[x][t[i]]=1;
    	for(rg int i=1;i<=n;i++)
    		if(i!=fa&&dd[x][i]){
    			dfs(i,x);
    			for(rg int j=1;j<=num;j++)
    			{
    				long long g=0;
    				for(rg int k=1;k<=num;k++)if(d[t[j]][t[k]])g+=f[i][t[k]];
    				f[x][t[j]]*=g;
    			}
    		}
    }
    int main()
    {
    	read(n),read(m),tot=1<<n;
    	for(rg int i=1,x,y;i<=m;i++)read(x),read(y),d[x][y]=d[y][x]=1;
    	for(rg int i=1,x,y;i<n;i++)read(x),read(y),dd[x][y]=dd[y][x]=1;
    	for(rg int i=0;i<tot;i++){
    		num=0;
    		for(rg int j=0;j<n;j++)if(i&(1<<j))t[++num]=j+1;
    		dfs(1,0);
    		for(rg int j=1;j<=num;j++)ans+=((n-num)&1?-1ll:1ll)*f[1][t[j]];
    	}
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    [国家集训队] Crash 的文明世界
    [国家集训队] middle
    [正睿集训2021] 构造专练
    [正睿集训2021] LIS
    CF482E ELCA
    UVA
    UVA
    UVA
    UVA
    UVA
  • 原文地址:https://www.cnblogs.com/lcxer/p/10800097.html
Copyright © 2020-2023  润新知