P4336-[SHOI2016]黑暗前的幻想乡【矩阵树定理,容斥】
生活随笔
收集整理的這篇文章主要介紹了
P4336-[SHOI2016]黑暗前的幻想乡【矩阵树定理,容斥】
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
正題
題目鏈接:https://www.luogu.com.cn/problem/P4336
題目大意
nnn個(gè)點(diǎn),n?1n-1n?1個(gè)邊集,求有多少種方案使得每個(gè)邊集中恰好選出一條邊使得這nnn個(gè)點(diǎn)連成一棵樹(shù)。
解題思路
我們需要利用好n?1n-1n?1個(gè)邊集這個(gè)性質(zhì),因?yàn)?span id="ozvdkddzhkzd" class="katex--inline">nnn很小,考慮容斥。
和[ZJOI2016]小星星那題一樣,如果對(duì)于kkk個(gè)邊集我們不選,那么就表示有kkk條邊是重復(fù)的,所以容斥系數(shù)就是(?1)k(-1)^k(?1)k。
枚舉去掉的邊集,然后剩下的用矩陣樹(shù)求答案即可。
時(shí)間復(fù)雜度O(2nn3)O(2^nn^3)O(2nn3),實(shí)際會(huì)小一些
codecodecode
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #define mp(x,y) make_pair(x,y) #define ll long long using namespace std; const ll N=20,P=1e9+7; ll n,a[N][N],ans; vector<pair<ll,ll> >q[N]; ll count(ll x){ll ans=0; while(x){ans++;x-=(x&-x);}return ans; } ll power(ll x,ll b){ll ans=1;while(b){if(b&1)ans=ans*x%P;x=x*x%P;b>>=1;}return ans; } void solve(ll p){memset(a,0,sizeof(a));for(ll i=1;i<n;i++){if((p>>i-1)&1)continue;for(ll j=0;j<q[i].size();j++){ll x=q[i][j].first,y=q[i][j].second;a[x][y]--;a[y][x]--;a[x][x]++;a[y][y]++;}}ll f=(count(p)&1)?-1:1,prod=1;for(ll i=1;i<n;i++){ll w=i;for(ll j=i;j<n;j++){if(a[i][j]){if(i!=j)f=-f;w=j;break;}}swap(a[i],a[w]);prod=prod*a[i][i]%P;if(!a[i][i])return;ll inv=power(a[i][i],P-2);for(ll j=i;j<n;j++)a[i][j]=a[i][j]*inv%P;for(ll j=i+1;j<n;j++){ll rate=P-a[j][i];for(ll k=i;k<n;k++)a[j][k]=(a[j][k]+rate*a[i][k]%P+P)%P;}}ans=(ans+prod*f+P)%P;return; } signed main() {scanf("%lld",&n);for(ll i=1;i<n;i++){ll m,x,y;scanf("%lld",&m);for(ll j=1;j<=m;j++){scanf("%lld%lld",&x,&y);q[i].push_back(mp(x,y));}}ll MS=(1<<n-1);for(ll i=0;i<MS-1;i++)solve(i);printf("%lld\n",ans);return 0; }總結(jié)
以上是生活随笔為你收集整理的P4336-[SHOI2016]黑暗前的幻想乡【矩阵树定理,容斥】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: P6178-[模板]Matrix-Tre
- 下一篇: P5516-[MtOI2019]小铃的烦