P3349-[ZJOI2016]小星星【树形dp,容斥】
生活随笔
收集整理的這篇文章主要介紹了
P3349-[ZJOI2016]小星星【树形dp,容斥】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
正題
題目鏈接:https://www.luogu.com.cn/problem/P3349
題目大意
nnn個點的一棵樹,再給出一張圖,樹上每個點對應圖上每個點后要求樹上的邊圖上都有,求有多少種對應方式。
解題思路
由于題目要求每個點只出現一次就加大了難度,可以考慮用容斥去掉這個限制。如果至少有kkk個點重復出現過,那么這種情況的容斥系數就為(?1)k(-1)^k(?1)k。
我們可以枚舉一個集合sss,那么sss中的所有點都不選,那么就至少會有∣s∣|s|∣s∣個點重復,容斥系數就為(?1)∣s∣(-1)^{|s|}(?1)∣s∣。然后上dpdpdp即可,這樣的時間復雜度大概是O(n∑s∈G∣s∣2)O(n\sum_{s\in G}|s|^2)O(n∑s∈G?∣s∣2)。
計算下來大概是1e71e71e7級別的,可以通過本題。
codecodecode
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=18; struct node{ll to,next; }a[N*2]; ll n,m,tot,s,ans,ls[N],f[N][N]; bool v[N][N]; void addl(ll x,ll y){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;return; } void dfs(ll x,ll fa){for(ll p=0;p<n;p++)if(!((1<<p)&s))f[x][p]=1;else f[x][p]=0;for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y==fa)continue;dfs(y,x);for(ll p=0;p<n;p++){ll tmp=0;if(s&(1<<p))continue;for(ll q=0;q<n;q++)tmp+=f[y][q]*v[p][q];f[x][p]*=tmp;}}return; } int main() {scanf("%lld%lld",&n,&m);ll MS=(1<<n);for(ll i=1;i<=m;i++){ll x,y;scanf("%lld%lld",&x,&y);x--;y--;v[x][y]=v[y][x]=1;}for(ll i=1;i<n;i++){ll x,y;scanf("%lld%lld",&x,&y);x--;y--;addl(x,y);addl(y,x);}for(s=0;s<MS;s++){dfs(0,0);ll tmp=0;for(ll i=0;i<n;i++)tmp+=f[0][i];ll w=s,z=1;while(w)w-=(w&-w),z=-z;ans+=z*tmp;}printf("%lld\n",ans); }總結
以上是生活随笔為你收集整理的P3349-[ZJOI2016]小星星【树形dp,容斥】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓手机如何将重要文件全部发送到桌面安卓
- 下一篇: 路由器怎么远程登录如何设置容许远程登录路