@codeforces - 1221G@ Graph And Numbers
@description@
给定一个 n 点 m 边的无向图。
现在要求给每个点写上 0 或 1,一条边的权值定义为该边连接的两点权值之和。
有多少种方案,使得存在至少一条边的权值为 0,至少一条边权值为 1,至少一条边权值为 2。
Input
第一行包含两个数 n 和 m (1≤n≤40, 0≤m≤n*(n−1)/2),表示点数与边数。
接下来 m 行,每行两个整数 xi 与 yi (1≤xi,yi≤n, xi≠yi),描述一条边的两个端点。
保证无重边。
Output
输出合法的方案个数。
Examples
input
6 5
1 2
2 3
3 4
4 5
5 1
output
20
input
4 4
1 2
2 3
3 4
4 1
output
4
@solution@
n <= 40 暗示 meet in the middle。要求的计数方案暗示容斥。
首先考虑怎么容斥,我们统计以下方案数量:
f1:没有任何限制。
f2:强制 0 不出现。
f3:强制 1 不出现。
f4:强制 2 不出现。
f5:强制 0 与 1 不出现。
f6:强制 0 与 2 不出现。
f7:强制 1 与 2 不出现。
f8:强制 0, 1 与 2 不出现。
最终答案 ans = f1 - f2 - f3 - f4 + f5 + f6 + f7 - f8。
接下来考虑具体怎么计数。
首先易得 f1 = 2^n。
如果所有连通分量大小都为 1,共有 m 个连通分量,则 f8 = 2^m;否则 f8 = 0。
如果所有连通分量都为二分图,共有 m 个连通分量,则 f6 = 2^m;否则 f6 = 0。
如果大小为 1 的连通分量个数为 k,则 f5 = f7 = 2^k。
如果总连通分量个数为 m,则 f3 = 2^m。
而剩下的 f2, f4 就需要双向搜索。因为 f2 = f4,我们不妨只考虑 f4。
假如点 u 的数值为 0,则它相邻的点不带限制;否则如果点 u 的数值为 1,它相邻的点只能为 0。
我们枚举前一半的二进制状态,得到哪些点必须为 0,进而判断当前状态是否合法。
记 f[s] 表示 s 是否合法,合法为 1,否则为 0;g[s] 表示二进制 s' <= s 的 f[s'] 之和,高维前缀和即可。
查询时枚举后一半的二进制状态,首先判断是否合法,然后得到前一半哪些为 0,哪些为 0 或 1。直接取 g 值即可。
@accepted code@
#include<cstdio>
#include<queue>
using namespace std;
typedef long long ll;
int n, m; ll G[40 + 5];
int fa[40 + 5], siz[40 + 5];
int find(int x) {
	return fa[x] = (fa[x] == x ? x : find(fa[x]));
}
void unite(int x, int y) {
	int fx = find(x), fy = find(y);
	if( fx != fy ) fa[fx] = fy, siz[fy] += siz[fx];
}
ll check(int x) {
	ll d[40 + 5] = {};
	for(int i=0;i<n;i++)
		d[i] = -1;
	queue<int>que; que.push(x); d[x] = 0;
	while( !que.empty() ) {
		int f = que.front(); que.pop();
		for(int i=0;i<n;i++)
			if( (G[f]>>i) & 1 ) {
				if( d[i] == -1 ) {
					d[i] = d[f] ^ 1;
					que.push(i);
				}
				else {
					if( d[i] != (d[f] ^ 1) )
						return 0;
				}
			}
	}
	return 2;
}
ll solve1() {
	ll ret1 = 1, ret2 = 1, ret3 = 1, ret4 = 1;
	for(int i=0;i<n;i++)
		if( fa[i] == i ) {
			ret1 <<= 1;
			ret2 = ret2*check(i);
			ret3 = (siz[i] == 1) ? (ret3<<1) : ret3;
			ret4 = (siz[i] == 1) ? (ret4<<1) : 0;
		}
	return ret2 - ret1 + (ret3<<1) - ret4;
}
ll f[1<<20];
void dfs1(int d, int mxd, int s1, int s2) {
	if( d == mxd ) {
		f[s1]++;
		return ;
	}
	dfs1(d + 1, mxd, s1, s2);
	if( !(s2 & (1LL<<d)) )
		dfs1(d + 1, mxd, s1|(1LL<<d), s2|G[d]);
}
int mid, t;
ll dfs2(int d, int mxd, ll s) {
	if( d == mxd ) {
		s = s & t, s = s ^ t;
		return f[s];
	}
	ll ret = dfs2(d + 1, mxd, s);
	if( !(s & (1LL<<d)) )
		ret += dfs2(d + 1, mxd, s|G[d]);
	return ret;
}
ll solve2() {
	mid = (n>>1), t = (1<<mid) - 1;
	dfs1(0, mid, 0, 0);
	for(int i=0;i<mid;i++)
		for(int j=0;j<=t;j++)
			if( j & (1LL<<i) ) f[j] += f[j^(1LL<<i)];
	return dfs2(mid, n, 0);
}
int main() {
	scanf("%d%d", &n, &m);
	for(int i=0;i<n;i++) fa[i] = i, siz[i] = 1;
	for(int i=1;i<=m;i++) {
		int x, y; scanf("%d%d", &x, &y), x--, y--;
		G[x] |= (1LL<<y), G[y] |= (1LL<<x), unite(x, y);
	}
	printf("%lld\n", (1LL<<n) + solve1() - (solve2()<<1));
}
@details@
一开始没有考虑到连通块大小为 1(即该连通块中没有边)的情况,WA 了一次。
然后因为没开 long long,WA 了好几次。
@codeforces - 1221G@ Graph And Numbers的更多相关文章
- [codeforces 55]D. Beautiful numbers
		[codeforces 55]D. Beautiful numbers 试题描述 Volodya is an odd boy and his taste is strange as well. It ... 
- Codeforces 1221 G Graph And Numbers
		题面 这种比赛时只有11个人做出来的题一般来说都是暴难的, 我也不知道我怎么搞出来的www 看完这个题第一感觉就是要容斥,至少有一条某种边的方案已经比较难求了,而直接算三种边都至少存在一条的方案数就更 ... 
- CodeForces - 1245A Good ol' Numbers Coloring (思维)
		Codeforces Round #597 (Div. 2 Consider the set of all nonnegative integers: 0,1,2,-. Given two integ ... 
- CodeForces 682A  Alyona and Numbers (水题)
		Alyona and Numbers 题目链接: http://acm.hust.edu.cn/vjudge/contest/121333#problem/A Description After fi ... 
- Codeforces 449D Jzzhu and Numbers
		http://codeforces.com/problemset/problem/449/D 题意:给n个数,求and起来最后为0的集合方案数有多少 思路:考虑容斥,ans=(-1)^k*num(k) ... 
- Codeforces gym101612 E.Equal Numbers(贪心)
		传送:http://codeforces.com/gym/101612 题意:给出一个大小为n的序列a[i],每次选其中一个数乘以一个正整数,问进行k步操作后最少剩下多少种数字,输出0≤k≤n,所有的 ... 
- Codeforces  817C Really Big Numbers - 二分法 - 数论
		Ivan likes to learn different things about numbers, but he is especially interested in really big nu ... 
- Codeforces 405E Graph Cutting
		Graph Cutting 不会写.. dfs的过程中把回边丢到它的祖先中去, 回溯的时候两两配对.感觉好神奇啊. #include<bits/stdc++.h> #define LL l ... 
- Codeforces 449D Jzzhu and Numbers(高维前缀和)
		[题目链接] http://codeforces.com/problemset/problem/449/D [题目大意] 给出一些数字,问其选出一些数字作or为0的方案数有多少 [题解] 题目等价于给 ... 
随机推荐
- canvas绘制video
			html <video style="position: relative; object-fit: fill;" preload="auto" id=& ... 
- Browsersync 浏览器自动刷新
			Browsersync 是一个很好用的工具,它可以实时监测文件的变动然后自动刷新浏览器,不用每次去点刷新或F5,特别在调试样式时非常有用. browsersync中文网 http://www.bro ... 
- Axure 工具的使用
			Axure RP是一款专业的快速原型设计工具,Axure RP是美国Axure Software Solution公司旗舰产品,是一个专业的快速原型设计工具,让负责定义需求和规格.设计功能和界面的专家 ... 
- nginx的四个基本功能
			Nginx能做什么 1.反向代理2.负载均衡3.HTTP服务器(包含动静分离)4.正向代理 以上就是做网站小编了解到的Nginx在不依赖第三方模块能处理的事情,下面详细说明每种功能怎么做 1.反向代理 ... 
- fiddler替换服务器上文件进行本地调试
			在我们前端开发的日常工作中,发现服务器上某个css/javascript文件有问题,需要修改,那真是家常便饭.通常,我们需要将文件进行修改,然后重新发布再验证,这样就很容易影响到生产环境的稳定性.更普 ... 
- C#调用C++ DLL动态库的两种方式
			第一种方式:C++导出函数, c#dllimport 的方式 在很多地方都看到过,如[dllimport "user32.dll"]这种代码,调用windows API,就是通过这 ... 
- netbeans生成的maven工程没有web.xml文件 如何新建
			使用netbeans生成的maven工程没有web.xml 需要自己新建 步骤: 下一步,完成 
- GIT → 00:GIT学习大纲
			1. 学习版本控制的原因 1.1 没有版本控制出现的问题 1.2 版本控制的简介 1.3 版本控制工具 2. Git 和 Svn 比较 2.1 SVN介绍 2.1.1 SVN简介 2.1.2 SVN基 ... 
- 2019.9.17 csp-s模拟测试45 反思总结
			来了来了,垃圾二连.[指两次发博客] 看了一下题就匆匆回去上课,在课上一边听课一边水oi,大概用1h40min的时间想完三道题.最后回到机房只剩下40min的时间敲代码,于是T1骗了70分就走了… 这 ... 
- django中模型
			一.django需要使用数据库,则需要安装对应的驱动,比如mysql,则需要安装mysqlclient驱动: pip install mysqlclient 二.在settings.py文件中配置数据 ... 
