time limit per test : 10.0 s
memory limit per test : 256 MB
In graph theory, a vertex cover of a graph
is a set of vertices
such that each edge of the graph is incident to at least one vertex of the set. That is to say, for every edge
of the graph, either
or
is in the vertex cover
.
Now, Kamilah shows you an undirected graph without loops or multiple edges, each vertex of which has a weight. She can evaluate a vertex cover of by the product of weights of all vertices belonging to S. Here, the product of an empty set (of numbers) is defined as .
You are asked to calculate the sum of the evaluations described above for all vertex covers of
.
Input
The input contains several test cases, and the first line is an integer indicating the number of test cases which is up to 3600.
For each test case, the first line contains three integers and which are the number of vertices and the number of edges in the graph , and which is a prime number for the output.
The second line contains integers, the -th of which is the weight of the -th vertices in . All weights are in the range of to .
Each of the following
lines contains two integers
and
describing an edge between the
-th vertex and the
-th one.
We guarantee that no more than
test cases satisfy
.
Output
For each test case, output a line containing KaTeX parse error: Expected 'EOF', got '#' at position 6: Case #̲x: y, where
is the test case number starting from
, and
is the remainder of the answer dividing by
.
Example
Input
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
Output
Case #1: 8
Case #2: 5
题意:
给定一个n个点m条边的无向图,这个图的一个点覆盖的价值为点集中所有点的权值的乘积,要求求出所有点覆盖的价值和。答案对q取模。
题解:
折半搜索+高维前缀和。
先把边分为前半区,后半区,连接前后半区,三种情况。
然后对于搜索出来的答案,在后半区中查找前半区的答案中符合当前情况的答案。
这个用高维前缀和维护即可。
#include<bits/stdc++.h>
#define ll long long
#define pa pair<int,int>
using namespace std;
int n,m;
ll mod;
int lc,rc,val[44];
ll f[1<<19];
ll ml[19],mr[19],mm[19];
int w33ha(int CASE){
memset(ml,0,sizeof(ml));
memset(mr,0,sizeof(mr));
memset(mm,0,sizeof(mm));
scanf("%d%d%lld",&n,&m,&mod);
lc=(n+1)/2;
rc=n-lc;
for(int i=0;i<n;i++)scanf("%d",&val[i]);
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
if(u>v)swap(u,v);
u--;v--;
if(u<lc&&v<lc) {
ml[u]|=(1<<v);
}
else if(u>=lc&&v>=lc){
mr[u-lc]|=(1<<(v-lc));
}
else mm[u]|=(1<<(v-lc));
}
for(int S=0;S<(1<<rc);S++){
ll res=1;
for(int i=0;i<rc;i++){
if(S&(1<<i))res=(res*val[lc+i])%mod;
else{
if((mr[i]|S)!=S)res=0;
}
}
f[S]=res;
}
ll ans=0;
for(int i=0;i<rc;i++){
for(int j=0;j<(1<<rc);j++){
if((j&(1<<i))==0)f[j]=(f[j]+f[j|(1<<i)])%mod;
}
}
for(int S=0;S<(1<<lc);S++){
ll res=1,tov=0;
for(int i=0;i<lc;i++){
if(S&(1<<i))res=(res*val[i])%mod;
else{
if((ml[i]|S)!=S){
// cout<<i<<" " << res << endl;
res=0;
}
tov|=mm[i];
}
}
// cout<<S<<" "<<tov << " " << res <<endl;
ans+=f[tov]*res;
ans%=mod;
}
printf("Case #%d: %lld\n",CASE,ans);
return 0;
}
int main(){
int T;scanf("%d",&T);
for(int i=1;i<=T;i++)w33ha(i);
return 0;
}