[LOJ2027] [SHOI2016] 黑暗前的幻想鄉
阿新 • • 發佈:2019-05-01
ref swap 一個 bits tps rst double uri www 乘個\((-1)^{n-1-cnt(s)}\)的系數加起來就好了。
題目鏈接
LOJ:https://loj.ac/problem/2027
洛谷:https://www.luogu.org/problemnew/show/P4336
Solution
這題很像[ZJOI2016]小星星,註意到如果沒有每個邊集選一條邊的限制的話,直接就是一個果的\(\rm matrix \ tree\)定理。
那麽有這個限制我們算出來的生成樹個數就會有不合法的情況,即一個邊集裏選多條邊,或者說沒有用到\(n-1\)個邊集。
那麽我們可以算出\(f[s]\)表示至考慮\(s\)狀態的這些邊集,隨便選的生成樹個數,那麽這些方案最多也就選到\(s\)這些邊集。
我們可以參照上題進行容斥,對每個\(f\)
#include<bits/stdc++.h> using namespace std; void read(int &x) { x=0;int f=1;char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f; } void print(int x) { if(x<0) putchar('-'),x=-x; if(!x) return ;print(x/10),putchar(x%10+48); } void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');} #define lf double #define ll long long #define pii pair<int,int > #define vec vector<int > #define pb push_back #define mp make_pair #define fr first #define sc second #define FOR(i,l,r) for(int i=l, i##_r=r;i<=i##_r;i++) const int maxn = 18; const int inf = 1e9; const lf eps = 1e-8; const int mod = 1e9+7; int add(int x,int y) {return x+y>=mod?x+y-mod:x+y;} int del(int x,int y) {return x-y<0?x-y+mod:x-y;} int mul(int x,int y) {return 1ll*x*y-1ll*x*y/mod*mod;} int qpow(int a,int x) { int res=1; for(;x;x>>=1,a=mul(a,a)) if(x&1) res=mul(res,a); return res; } int inv(int x) {return qpow(x,mod-2);} int n,r[maxn][maxn],a[18][400],b[18][400],ans; void ins(int u,int v) {r[u][u]++,r[v][v]++,r[u][v]--,r[v][u]--;} int calc() { int tmp=1; FOR(i,1,n-1) { if(!r[i][i]) FOR(j,i+1,n-1) if(r[j][i]) { FOR(k,1,n-1) swap(r[i][k],r[j][k]);tmp=-tmp;break; } FOR(j,1,i-1) { int res=mul(r[i][j],inv(r[j][j])); FOR(k,1,n-1) r[i][k]=del(r[i][k],mul(res,r[j][k])); } }if(tmp==-1) tmp=mod-1; FOR(i,1,n-1) tmp=mul(tmp,r[i][i]); return tmp; } void solve(int s) { memset(r,0,sizeof r); FOR(i,1,n-1) if(s&(1<<(i-1))) FOR(j,1,a[i][0]) ins(a[i][j],b[i][j]); ans=((n-1-__builtin_popcount(s))&1?del:add)(ans,calc()); } int main() { read(n); FOR(i,1,n-1) { read(a[i][0]); FOR(j,1,a[i][0]) read(a[i][j]),read(b[i][j]); }FOR(s,1,(1<<(n-1))-1) solve(s); write(ans); return 0; }
[LOJ2027] [SHOI2016] 黑暗前的幻想鄉