题目背景

$Billions\ of\ lighthouses...stuck\ at\ the\ far\ end\ of\ the\ sky.$


题目描述

平面有$n$个灯塔,初始时两两之间可以相互交流;但由于地形原因,有$m$对灯塔之间无法进行直接的交流。也就是一张完全图缺少了$m$条边。
    $River$想把这$n$个灯塔连成一个环,使得$n$个等他都在环上,并且环上相邻的两个灯塔能进行直接交流。$River$想知道这样做的方案数是多少,两种方案被认为是不同的,当且仅当有两个灯塔$u,v$,他们在一种方案中在环上相邻,而在另一种方案中相反。
    答案可能很大,你只需要输出对${10}^9+7$取模的结果。


输入格式

第一行两个整数$n,m$。
接下来$m$行,每行描述一条缺少的边。


输出格式

一行一个整数表示答案。


样例

样例输入1:

4 1
1 2

样例输出1:

1

样例输入2:

10 3
1 9
3 8
2 7

样例输出2:

87840


数据范围与提示

样例$1$解释:

唯一的方案是(1,3,2,4)依次连成环。

数据范围:

对于所有数据,有$3\leqslant n\leqslant {10}^7,0\leqslant m\leqslant \min(20,\frac{n(n-1)}{2})$。输入的边中没有重边。


题解

题目实际上球的就是哈密顿回路的数量。由于$m$很小,考虑容斥。
    枚举删除的边的某个子集$S$,设$f_S$表示有多少条哈密顿回路至少包含$S$集合中的边,答案就是$\sum_S(-1)^{|S|}\times f_S$。
    怎么算$f_S$呢?首先判掉$f_S=0$的情况,这包含以下两种情况:
        $\alpha.$仅考虑$S$中的边时,某个点的度数大于$2$。
        $\beta.$出现了环,并且这个环的大小不为$n$。
    特判掉$S$本身就是一个哈密顿回路的情况;假设$S$中的边构成了$k$条链,那么$f_S=s{k-1}\times (n-|S|-1)!$。
    证明:考虑将一条链看成一个点,那么总共有$n-|S|$个点,其环排列方案数为$(n-|S|-1)!$;每条链都可以翻转,因此乘上$2^k$;又由于一条哈密顿回路对应了两个环排列(正反两个方向),还要除以$2$。

时间复杂度:$\Theta(2^m\times m)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
int n,m;
long long jc[10000001];
int fa[10000001];
pair<int,int> pos[10000001];
int tot;
long long ans;
int cnt[10000001],vis[10000001],g[10000001];
int que[10000001];
map<pair<int,int>,bool> h;
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
long long qpow(long long x,long long y)
{long long res=1;while(y){if(y&1)res=res*x%1000000007;x=x*x%1000000007;y>>=1;}return res;}
long long solve(int x)
{
int sum=0,k=que[0]=0;
bool flag=0;
for(int i=1;i<=tot;i++)
if((x>>(i-1))&1)
{
que[++que[0]]=i;
fa[pos[i].first]=pos[i].first;
fa[pos[i].second]=pos[i].second;
vis[pos[i].first]=vis[pos[i].second]=g[pos[i].first]=g[pos[i].second]=0;
}
for(int i=1;i<=que[0];i++)
{
if(!vis[pos[que[i]].first])sum++;
if(!vis[pos[que[i]].second])sum++;
if(vis[pos[que[i]].first]==2||vis[pos[que[i]].second]==2)return 0LL;
vis[pos[que[i]].first]++;
vis[pos[que[i]].second]++;
}
for(int i=1,u,v;i<=que[0];i++)
{
if((u=find(pos[que[i]].first))==(v=find(pos[que[i]].second)))flag=1;
fa[u]=v;
}
for(int i=1,u;i<=que[0];i++)
if(!g[u=find(pos[que[i]].first)]){g[u]=1;k++;}
if(flag&&(cnt[x]!=n||k>1))return 0LL;
long long res=jc[n-sum+k-1]*qpow(2,k)%1000000007*qpow(2,1000000005)%1000000007;
return (cnt[x]&1)?-res:res;
}
int main()
{
jc[0]=1;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
if(x==y||h[make_pair(x,y)])continue;
h[make_pair(x,y)]=1;
pos[++tot]=make_pair(x,y);
}
for(int i=1;i<=n;i++)jc[i]=1LL*i*jc[i-1]%1000000007;
for(int i=0;i<(1<<tot);i++)cnt[i]=cnt[i>>1]+(i&1);
for(int i=0;i<(1<<tot);i++)ans=(ans+solve(i))%1000000007;
printf("%lld",(ans+1000000007)%1000000007);
return 0;
}

rp++

[CSP-S模拟测试]:Lighthouse(哈密顿回路+容斥)的更多相关文章

  1. [CSP-S模拟测试]:阴阳(容斥+计数+递推)

    题目传送门(内部题16) 输入格式 第一行两个整数$n$和$m$,代表网格的大小.接下来$n$行每行一个长度为$m$的字符串,每个字符若为$W$代表这个格子必须为阳,若为$B$代表必须为阴,若为$?$ ...

  2. [CSP-S模拟测试]:多维网格(组合数学+容斥)

    题目传送门(内部题138) 输入格式 输入数据第一行为两个整数$d,n$. 第二行$d$个非负整数$a_1,a_2,...,a_d$.     接下来$n$行,每行$d$个整数,表示一个坏点的坐标.数 ...

  3. [CSP-S模拟测试]:连连看(图论+容斥)

    题目传送门(内部题74) 输入格式 输入文件$link.in$ 第一行三个整数$n,m,k$,之间用空格隔开,$n,m$表示地图行数和列数,$k$表示每个方块周围相邻的位置(至多有$4$个,至少有$2 ...

  4. [CSP-S模拟测试]:建设城市(city)(组合数学+容斥)

    题目传送门(内部题8) 输入格式 一行三个整数$n,m,k$. 输出格式 一行一个整数表示答案.对$998244353$取模. 样例 样例输入 3 7 3 样例输出 数据范围与提示 对于10%的数据, ...

  5. csp-s模拟测试59(10.4)「Reverse」(set)·「Silhouette」(容斥)

    A. Reverse 菜鸡wwb又不会了..... 可以线段树优化建边,然而不会所以只能set水了 发现对于k和当前反转点固定的节点x确定奇偶性所到达的节点奇偶性是一定的 那么set维护奇偶点,然后每 ...

  6. 【GDOI2016模拟3.16】幂(容斥 + 模型复杂转化)

    [GDOI2016模拟3.16]幂 \(X\in[1,A],Y\in[1,B]\),问:\(x^y\)的不用取值个数. \(A,B\)都是\(10^9\)级别. 然后我们开搞. 首先,假设一个合法的\ ...

  7. hdu 6169 Senior PanⅡ Miller_Rabin素数测试+容斥

    Senior PanⅡ Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others) Pr ...

  8. 2018.10.30 NOIP模拟 字胡串(单调栈+容斥)

    传送门 对于每个点,用单调栈求出它左右第一个比他大的位置. 然后对每个点O(logai)O(log_{a_i})O(logai​​)求出第一个拥有跟它不同二进制位的位置. 然后容斥一下就行了. 代码

  9. NOIp模拟赛 巨神兵(状压DP 容斥)

    \(Description\) 给定\(n\)个点\(m\)条边的有向图,求有多少个边集的子集,构成的图没有环. \(n\leq17\). \(Solution\) 问题也等价于,用不同的边集构造DA ...

随机推荐

  1. 使用定时器settimeout、setInterval执行能传递参数的函数

    无论是window.setTimeout还是window.setInterval,在使用函数名作为调用句柄时都不能带参数,而在许多场合必须要带参数,这就需要想方法解决.经网上查询后整理如下: 例如对于 ...

  2. 阅读笔记05-架构师必备最全SQL优化方案(1)

    一.优化的哲学 1.优化可能带来的问题? 优化不总是对一个单纯的环境进行,还很可能是一个复杂的已投产的系统: 优化手段本来就有很大的风险,只不过你没能力意识到和预见到: 任何的技术可以解决一个问题,但 ...

  3. Decision Tree Algorithm

    Decision Tree算法的思路是,将原始问题不断递归地细分为子问题,直到子问题直接可获得答案为止.在模型训练的过程中,根据训练集去做树的生长(Grow the tree),生长所有可能的Bran ...

  4. HTML DOM cursor 属性

    值 描述 url 需被使用的自定义光标的URL 注释:请在此列表的末端始终定义一种普通的光标,以防没有由 URL 定义的可用光标. default 默认光标(通常是一个箭头) auto 默认.浏览器设 ...

  5. php优化方法

    代码优化是开发程序和网站必不可少的一步,代码优化好了,可以大大增加程序的运行效率.使网站或程序加载反应更快.用户体验也就会更好.下面就为大家总结了50条PHP代码优化技巧. 1. 用单引号代替双引号来 ...

  6. 2.etcd集群的安装(cfssl版)

    etcd的安装注意两点 1.systemd的配置文件   2. 证书 1. 解决 systemd的问题,想安装指定版本的etcd可以通过 yum方式安装 etcd 可以获得 systemc 和 etc ...

  7. proxool连接池配置方法

    proxool.properties: jdbc-1.proxool.alias=test #jdbc-1.proxool.driver-class=com.mysql.jdbc.Driver #jd ...

  8. 合并石子 (区间dp+前缀和)

    [题目描述] N堆石子.现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分.计算出将N堆石子合并成一堆的最小得分. [题目链接] http: ...

  9. wireshark自动化之tshark命令行

    tshark是wireshark安装目录下命令行工具 使用tshark可以通过自动化方式调用wireshark tshark -a duration:30 抓包30秒-w cap.cap 保存为cap ...

  10. ModbusTcp踩得坑

    单元标识符在MODBUS或MODBUS+串行链路子网中对设备进行寻址时,这个域是用于路由的目的.在这种情况下,“Unit Identifier”携带一个远端设备的MODBUS从站地址:- 如果MODB ...