JAG2015 ICPC Teams

You are a coach of the International Collegiate Programming Contest (ICPC) club in your university.
There are 3N students in the ICPC club and you want to make N teams for the next ICPC. All teams in
ICPC consist of 3 members. Every student belongs to exactly one team.
When you form the teams, you should consider several relationships among the students. Some student
has an extremely good relationship with other students. If they belong to a same team, their performance
will improve surprisingly. The contrary situation also occurs for a student pair with a bad relationship.
In short, students with a good relationship must be in the same team, and students with a bad relationship
must be in different teams. Since you are a competent coach, you know all M relationships among the
students.
Your task is to write a program that calculates the number of possible team assignments. Two assignments
are considered different if and only if there exists a pair of students such that in one assignment they are
in the same team and in the other they are not.
Input
The input consists of a single test case. The first line contains two integers N (1 N 10
6
) and M
(1 M 18). The i-th line of the following M lines contains three integers Ai
, Bi
(1 Ai
; Bi 3N,
Ai , Bi
), and Ci (Ci 2 f0; 1g). Ai
and Bi
denote indices of the students and Ci
denotes the relation type.
If Ci
is 0, the Ai
-th student and the Bi -th student have a good relation. If Ci
is 1, they have a bad relation.
You can assume that fAi
; Bi g , fA j
; B j g if i , j for all 1 i; j M.
Output
Display a line containing the number of the possible team assignments modulo 10
9
+ 9.
Sample Input 1
2 2
1 2 0
3 4 1

#include <bits/stdc++.h>
 
#define long long long
#define LOOPVAR_TYPE long
 
#define all(x) (x).begin(), (x).end()
#define max(x, y) ((x) > (y) ? (x) : (y))
#define min(x, y) ((x) < (y) ? (x) : (y))
#define sz(x) ((LOOPVAR_TYPE)(x).size())
#define foreach(it, X) for(__typeof((X).begin()) it = (X).begin(); it != (X).end(); it++)
#define GET_MACRO(_1, _2, _3, NAME, ...) NAME
#define _rep(i, n) _rep2(i, 0, n)
#define _rep2(i, a, b) for(LOOPVAR_TYPE i = (LOOPVAR_TYPE)(a); i < (LOOPVAR_TYPE)(b); i++)
#define rep(...) GET_MACRO(__VA_ARGS__, _rep2, _rep)(__VA_ARGS__)
 
#define fir first
#define sec second
#define mp make_pair
#define mt make_tuple
#define pb push_back
 
const double EPS = 1e-9;
const double PI = acos(-1.0);
const long INF = 1070000000LL;
const long MOD = 1000000009LL;
 
using namespace std;
 
typedef istringstream iss;
typedef stringstream sst;
typedef pair<LOOPVAR_TYPE, LOOPVAR_TYPE> pi;
typedef vector<LOOPVAR_TYPE> vi;
 
//
int par_uf[1000010],rank_uf[1000010];
 
void init(int n){for(int i=0;i<n;i++){par_uf[i]=i;rank_uf[i]=0;}}
int find(int x){if(par_uf[x]==x)return x;else return par_uf[x]=find(par_uf[x]);}
void unite(int x,int y){x=find(x);y=find(y);if(x==y)return;if(rank_uf[x]<rank_uf[y])par_uf[x]=y;else{par_uf[y]=x;if(rank_uf[x]==rank_uf[y])rank_uf[x]++;}}
bool same(int x,int y){return find(x)==find(y);}
//
 
int N, M;
int M0,a0[20],b0[20],c0[20];
int M1,a1[20],b1[20],c1[20];
int conv[3000010];
long way3[1000010];
 
int main(){
	cin.tie(0);
	ios_base::sync_with_stdio(0);
	
	cin>>N>>M;
	memset(conv,-1,sizeof(conv));
	int cur = 0;
	rep(i,M){
		int a,b,c;
		cin>>a>>b>>c;
		a--; b--;
		if(c == 1) a0[M0] = a, b0[M0] = b, c0[M0] = c, M0++;
		else a1[M1] = a, b1[M1] = b, c1[M1] = c, M1++;
		if(conv[a] == -1){
			conv[a] = cur++;
		}
		if(conv[b] == -1){
			conv[b] = cur++;
		}
	}
	way3[0] = 1;
	rep(i,N){
		way3[i+1] = way3[i] * (3*i+2) % MOD * (3*i+1) % MOD * 500000005 % MOD;
	}
	long ans = 0;
	rep(mask, 1<<M0){
		init(cur);
		rep(i,M0){
			if(mask >> i & 1){
				unite(conv[a0[i]], conv[b0[i]]);
			}
		}
		rep(i,M1){
			unite(conv[a1[i]], conv[b1[i]]);
		}
		int g[36] = {};
		rep(i,cur){
			g[find(i)]++;
		}
		int fail = 0;
		int rest = 3*N;
		int two = 0;
		rep(i,cur){
			if(g[i] > 3){
				fail = 1;
				break;
			}
			if(g[i] == 3){
				rest -= 3;
			}
			if(g[i] == 2){
				rest -= 2;
				two++;
			}
		}
		if(fail)continue;
		long way = way3[(rest - two)/3];
		rep(i,two){
			way = way * (rest - i) % MOD;
		}
		ans += __builtin_popcount(mask) % 2 ? MOD - way : way;
	}
	ans %= MOD;
	cout<<ans<<endl;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值