bzoj4455:[Zjoi2016]小星星
阿新 • • 發佈:2019-05-01
每次 char 代碼 重復 getc register 容斥 傳送門 efi
傳送門
考慮假如不考慮重復映射
那麽顯然可以得到一個\(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\n",ans); }
bzoj4455:[Zjoi2016]小星星