1. 程式人生 > >BZOJ 4596: [Shoi2016]黑暗前的幻想鄉

BZOJ 4596: [Shoi2016]黑暗前的幻想鄉

迷之正確性的做法

首先觀察資料範圍,哎和ZJOI的小星星一毛一樣啊,會不會給人一種欽定複雜度的感覺啊

於是就亂搞一發,容斥+Matrix Tree定理

莫名其妙地就過了QAQ

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<stack>
#include<cstdlib>
#include<ctime>
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
#define mmt(a,v) memset(a,v,sizeof(a))
#define tra(i,u) for(int i=head[u];i;i=e[i].next)
using namespace std;
typedef long long ll;
typedef pair<int,int> pr;
#define mk(x,y) make_pair(x,y)
const int N=20;
const int p=(1e9)+7;
ll g[N][N];
int n;
void print(){
	rep(i,1,n){
		rep(j,1,n)printf("%lld ",g[i][j]);
		puts("");
	}
}
ll iabs(ll x){return x<0?-x:x;}
ll Gauss(){
	ll ans=1;
	rep(i,1,n-1){
		rep(j,i+1,n-1)
		while(g[j][i]){
			ll t=g[i][i]/g[j][i];
			rep(k,i,n-1)
			g[i][k]=(g[i][k]-g[j][k]*t)%p;
			rep(k,i,n-1)
			swap(g[i][k],g[j][k]);
			ans=-ans;
		}
		ans=ans*g[i][i]%p;
		if(!ans)return 0;
	}
	return (ans+p)%p;
}
vector<pr >pl[N];
int main(){
	scanf("%d",&n);
	rep(i,1,n-1){
		int m;scanf("%d",&m);
		while(m--){int u,v;scanf("%d%d",&u,&v);pl[i].push_back(mk(u,v));}
	}
	ll ans=0;
	per(i,(1<<(n-1))-1,0){
		int cnt=0;
		mmt(g,0);
		rep(j,1,n-1)
		if(i>>(j-1)&1){
			per(k,(int)pl[j].size()-1,0){
				int u=pl[j][k].first,v=pl[j][k].second;
				g[u][u]++;g[v][v]++;
				g[u][v]--;g[v][u]--;
			}
			cnt++;
		}
		if((n-cnt)&1)ans=(ans+Gauss())%p;
		else ans=(ans-Gauss())%p;
	}
	printf("%lld\n",(ans+p)%p);
	return 0;
}