JZOJ 5839. 【省选模拟2018.8.22】Lighthouse


题意:给定一张n个点,m条边的无向图,问补图的本质不同的哈密顿回路个数

一看数据范围,$m \le 20$,再看题意,计数问题,那么很大概率就是容斥了……

一个显然的容斥:$ans=\sum_{s \subseteq S} (-1)^{\mid s \mid}f_s$,其中$S$表示所有给定边的集合,$f_s$表示至少选择了$s$中的边的哈密顿回路个数

注释:$n$个点的圆排列个数为$\frac{n!}{n}=(n-1)!$

显然有$f_s=\frac{(n-tot+k-1)! \times 2^k}{2}$,其中$tot$表示这些边中有多少个不同的点,$k$表示这些边形成多少条链

注意判断$f_s=0$的情况(无解)

 1 #include "bits/stdc++.h"
 2 using namespace std;
 3 typedef long long ll;
 4 const int N = 1e7 + 10, mod = 1e9 + 7;
 5 int fa[N], x[N], y[N], n, m, sz[N];
 6 int get(int x) { return x == fa[x] ? x : fa[x] = get(fa[x]); }
 7 int cnt[N], vis[N], deg[N], g[N];
 8 ll fac[N];
 9 ll ans;
10 ll pw(ll a, ll b) {
11     ll r = 1;
12     for( ; b ; b >>= 1, a = a * a % mod) if(b & 1) r = r * a % mod;
13     return r;
14 }
15 ll sol(int s) {
16     ll res = 0;
17     int flag = 0, k = 0, sum = 0;
18     for(int i = 1 ; i <= m ; ++ i) {
19         if((s >> (i - 1)) & 1) {
20             int u = x[i], v = y[i];
21             fa[u] = u, fa[v] = v;
22             vis[u] = 0, vis[v] = 0;
23             deg[u] = 0, deg[v] = 0;
24             g[u] = 0, g[v] = 0;
25         }
26     }
27     for(int i = 1 ; i <= m ; ++ i) {
28         if((s >> (i - 1)) & 1) {
29             int u = x[i], v = y[i];
30             if(deg[u] == 0) ++ sum;
31             if(deg[v] == 0) ++ sum;
32             if((++ deg[u]) >= 3 || (++ deg[v]) >= 3) return 0;
33         }
34     }
35     for(int i = 1 ; i <= m ; ++ i) {
36         if((s >> (i - 1)) & 1) {
37             int u = get(x[i]), v = get(y[i]);
38             if(u == v) flag = 1;
39             fa[u] = v;
40         }
41     }
42     for(int i = 1 ; i <= m ; ++ i) {
43         if((s >> (i - 1)) & 1) {
44             int u = get(x[i]);
45             if(!g[u]) {
46                 g[u] = 1;
47                 ++ k;
48             }
49         }
50     }
51     if(flag && (cnt[s] != n || k > 1)) {
52         return 0;
53     }
54     res = fac[n - sum + k - 1] * pw(2, k) % mod * pw(2, mod - 2) % mod;
55     if(cnt[s] & 1) res = -res;
56     return res;
57 }
58 
59 int main() {
60     freopen("lighthouse.in", "r", stdin);
61     freopen("lighthouse.out", "w", stdout);
62     scanf("%d%d", &n, &m);
63     for(int i = 0 ; i < (1 << m) ; ++ i) cnt[i] = cnt[i >> 1] + (i & 1);
64     for(int i = fac[0] = 1 ; i <= n ; ++ i) fac[i] = fac[i - 1] * i % mod;
65     for(int i = 1 ; i <= m ; ++ i) scanf("%d%d", &x[i], &y[i]);
66     for(int s = 0 ; s < (1 << m) ; ++ s) {
67         ll t = sol(s);
68         ans = (ans + t) % mod;
69     }
70     ans = (ans % mod + mod) % mod;
71     printf("%lld\n", ans);
72 }
JZOJ 5839. 【省选模拟2018.8.22】Lighthouse

转载于:https://www.cnblogs.com/KingSann/articles/9523091.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值