Vertex Covers(高维前缀和)
Vertex Covers
时间限制: 5 Sec 内存限制: 128 MB
提交: 5 解决: 3
题目描述
Now, Kamilah shows you an undirected graph G without loops or multiple edges, each vertex of which has a weight.She can evaluate a vertex cover S of G by the product of weights of all vertices belonging to S.Here, the product of an empty set (of numbers) is defined as 1.
You are asked to calculate the sum of the evaluations described above for all vertex covers of G.
输入
For each test case, the first line contains three integers n (1≤n≤36) and m (0≤m≤n(n − 1)/2) which are the number of vertices and the number of edges in the graph G, and q (108≤q≤109 ) which is a prime number for the output.
The second line contains n integers, the i-th of which is the weight of the i-th vertices in G. All weights are in the range of 1 to 109 .
Each of the following m lines contains two integers u and v (1≤u, v≤n) describing an edge between the u-th vertex and the v-th one.
We guarantee that no more than 36 test cases satisfy n > 18.
输出
样例输入
2
4 3 998244353
1 1 1 1
1 2
2 3
3 4
4 6 998244353
1 1 1 1
1 2
1 3
1 4
2 3
2 4
3 4
样例输出
Case #1: 8
Case #2: 5
题意:设一个图的点覆盖的贡献是该点覆集中点权的积,求一个图的所有点覆盖的贡献和。
思路(来自题解):
考虑折半,将点集分为大小接近的两部分 L 和 R,那么边集 分为 L 内部的、R 内部的以及 L 和 R 之间的。
枚举 L 的子集 S,检查是否 L 内部所有边都被覆盖。
再枚举 R 的子集 T,检查是否 R 内部所有边都被覆盖,如果是,那么根据 L 和 R 之间的未覆盖边可以知道 L 的一个合法的子集 T′ 必须要覆盖掉当前的未覆盖边,那么可以在 L 内选出所 有包含 T′ 的可行 S,这样 S+T 就是一个 vertex cover。
由于乘法满足分配率,只需要对 S 做一个高维前缀和就能 快速计算答案。
#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
using namespace std; const int N = ;
long long arr[N];
long long pre[<<]={}; unsigned long long Map[N]={}; int check(int x,int l,int r)
{
for(int i=l;i<=r;i++)
{
if(((<<i)&x)==)
{
unsigned long long now=((Map[i]<<(-r))>>(-r));
if((now&x)!=now)return ;
}
}
return ;
} int check2(int x,int l,int r,int mid)
{
for(int i=l;i<=r;i++)
{
if(((<<i)&x)==)
{
long long now=(Map[i+mid]>>mid);
if((now&x)!=now)return ;
}
}
return ;
} int main()
{
int t,Ca=;
scanf("%d",&t); while(t--)
{
int n,m;
long long mod;
scanf("%d %d %lld",&n,&m,&mod); for(int i=;i<n;i++)scanf("%lld",&arr[i]); memset(Map,,sizeof(Map));
while(m--)
{
int u,v;
scanf("%d %d",&u,&v);
u--;
v--;
Map[u]|=1ll<<v;
Map[v]|=1ll<<u;
} int mid=n/; for(int i=(<<mid)-;i>=;i--)pre[i]=; int upper=(<<mid)-; for(int i=;i<=upper;i++)
{
long long sum=;
for(int j=;j<mid;j++)
if((<<j)&i)sum=(sum*arr[j])%mod; if(check(i,,mid-))pre[i]=sum;
} for(int i=;i<mid;i++) //高维后缀和
for(int j=upper;j>=;j--)
if((j&(<<i))==) pre[j]=(pre[j]+pre[j^(<<i)])%mod; upper=(<<(n-mid))-; long long ans=;
for(int i=;i<=upper;i++)
{
long long sum=;
for(int j=;j<n-mid;j++)
if((<<j)&i)sum=(sum*arr[j+mid])%mod; if(check2(i,,n-mid-,mid))
{
long long base=;
for(int x=;x<=mid-;x++)
{
unsigned long long now=(Map[x]>>mid);
if((now&i)!=now)base|=<<x;
}
ans=(ans+sum*pre[base]%mod)%mod;
}
}
printf("Case #%d: %lld\n",Ca++,ans);
}
return ;
}
Vertex Covers(高维前缀和)的更多相关文章
- BZOJ.5092.[Lydsy1711月赛]分割序列(高维前缀和)
题目链接 \(Description\) \(Solution\) 首先处理\(a_i\)的前缀异或和\(s_i\).那么在对于序列\(a_1,...,a_n\),在\(i\)位置处分开的价值为:\( ...
- HDU.5765.Bonds(DP 高维前缀和)
题目链接 \(Description\) 给定一张\(n\)个点\(m\)条边的无向图.定义割集\(E\)为去掉\(E\)后使得图不连通的边集.定义一个bond为一个极小割集(即bond中边的任意一个 ...
- SPOJ.TLE - Time Limit Exceeded(DP 高维前缀和)
题目链接 \(Description\) 给定长为\(n\)的数组\(c_i\)和\(m\),求长为\(n\)的序列\(a_i\)个数,满足:\(c_i\not\mid a_i,\quad a_i\& ...
- LOJ2542 PKUWC2018 随机游走 min-max容斥、树上高斯消元、高维前缀和、期望
传送门 那么除了D1T3,PKUWC2018就更完了(斗地主这种全场0分的题怎么会做啊) 发现我们要求的是所有点中到达时间的最大值的期望,\(n\)又很小,考虑min-max容斥 那么我们要求从\(x ...
- Luogu3175 HAOI2015 按位或 min-max容斥、高维前缀和、期望
传送门 套路题 看到\(n \leq 20\),又看到我们求的是最后出现的位置出现的时间的期望,也就是集合中最大值的期望,考虑min-max容斥. 由\(E(max(S)) = \sum\limits ...
- BZOJ5092:[Lydsy1711月赛]分割序列(贪心,高维前缀和)
Description 对于一个长度为n的非负整数序列b_1,b_2,...,b_n,定义这个序列的能量为:f(b)=max{i=0,1,...,n}((b_1 xor b_2 xor...xor b ...
- HihoCoder - 1496:寻找最大值(高维前缀和||手动求子集)
描述 给定N个数A1, A2, A3, ... AN,小Ho想从中找到两个数Ai和Aj(i ≠ j)使得乘积Ai × Aj × (Ai AND Aj)最大.其中AND是按位与操作. 小Ho当然知道怎么 ...
- BZOJ:5092 [Lydsy1711月赛]分割序列(贪心&高维前缀和)
Description 对于一个长度为n的非负整数序列b_1,b_2,...,b_n,定义这个序列的能量为:f(b)=max{i=0,1,...,n}((b_1 xor b _2 xor...xor ...
- BZOJ4036:按位或 (min_max容斥&高维前缀和)
Description 刚开始你有一个数字0,每一秒钟你会随机选择一个[0,2^n-1]的数字,与你手上的数字进行或(c++,c的|,pascal 的or)操作.选择数字i的概率是p[i].保证0&l ...
随机推荐
- <每日一题>题目12:列表解析及zip、dict函数的简单应用
''' 分析: 1.列表解析:迭代机制的一种应用 语法: [expression for iter_val in iterable] [expression for iter_val in itera ...
- Python学习之--迭代器、生成器
迭代器 迭代器是访问集合元素的一种方式.从对象第一个元素开始访问,直到所有的元素被访问结束.迭代器只能往前,不能往后退.迭代器与普通Python对象的区别是迭代器有一个__next__()方法,每次调 ...
- iOS开发系列-线程状态
概述 线程从创建到销毁中间存在很多种状态. 线程的状态 通过NSThread创建一条线程,开发者需要负责线程的创建和执行,线程的销毁由系统决定.创建一个继承NSThread的FMThread类,重写d ...
- Linux 实用指令(5)--组管理和权限管理
目录 组管理和权限管理 1 Linux组基本介绍 2 文件/目录 所有者 2.1 查看文件的所有者 2.2 修改文件所有者 3 组的创建 3.1 基本指令 3.2 应用实例 4 文件/目录 所在组 4 ...
- UMP系统功能 资源调度
- Python全栈开发:web框架之tornado
概述 Tornado 是 FriendFeed 使用的可扩展的非阻塞式 web 服务器及其相关工具的开源版本.这个 Web 框架看起来有些像web.py 或者 Google 的 webapp,不过为了 ...
- Bootstrap Paginator分页插件(mark)
Bootstrap Paginator分页插件
- Tensorflow入门篇
参考Tensorflow中文网(http://www.tensorfly.cn/tfdoc/get_started/introduction.html) ,写一个入门. 1.打开pyCharm,新建 ...
- Git婴幼儿使用手册【十分钟让你帅气的使用命令行和团队工作】
Git由来:...... Git使用的好处:...... 如何使用Git:(以上会显得我们以下的是很纯纯的干货) 代码库有两个部分: 本地代码库:远程代码库: 本地代码库使用方法: 一.先创建一个文件 ...
- Pandas系列-读取csv/txt/excel/mysql数据
本代码演示: pandas读取纯文本文件 读取csv文件 读取txt文件 pandas读取xlsx格式excel文件 pandas读取mysql数据表 import pandas as pd 1.读取 ...