BZOJ4671: 异或图

$1 \leq s \leq 60$个$2 \leq n \leq 10$的图,定义图的异或是:如果一条边在两个图中出现次数和为1,那么异或后的图中存在这条边,否则不存在。问有多少图的集合满足异或后的图是连通图。

暂时自己推不动的题系列QAQ

容斥一发,枚举点集划分,然后强行让在不同点集的点不连边而同一点集内的点随意。如此一来,假如有一种真实的方案,它把图真真切切的变成了$m$个连通块,那么这种方案会被统计$\sum_{i=1}^m\begin{Bmatrix} m \\  i \end{Bmatrix}$次,就是,每次把分完的点集合再拿去分集合,然后会分到若干大集合,然后因为大集合里的点是乱连的,所以会算到这种情况。需要系数$f(i)$,满足$\sum_{i=1}^m\begin{Bmatrix} m \\  i \end{Bmatrix} f(i)=[m=1]$。

用斯特林数递推求这个系数当然没问题,但打表后可得$f(i)=(-1)^{i-1}(i-1)!$,简要证明:

$\sum_{i=1}^{m}\begin{Bmatrix} m\\ i\end{Bmatrix}(-1)^{i-1}(i-1)!$
$\\ =\sum_{i=1}^{m}(-1)^{i-1}(i-1)!(\begin{Bmatrix} m-1\\ i-1\end{Bmatrix}+i\begin{Bmatrix} m-1\\ i\end{Bmatrix})$
$\\ =\sum_{i=1}^{m}(-1)^{i-1}(i-1)!\begin{Bmatrix} m-1\\ i-1\end{Bmatrix}+\sum_{i=1}^{m}(-1)^{i-1}i!\begin{Bmatrix} m-1\\ i\end{Bmatrix}$
$\\ =\sum_{i=0}^{m-1}(-1)^ii!\begin{Bmatrix} m-1\\ i\end{Bmatrix}+\sum_{i=1}^{m-1}(-1)^{i-1}i!\begin{Bmatrix} m-1\\ i\end{Bmatrix}$
$\\ =[m=1]$

好的0.0

然后一个点集划分怎么求满足的方案呢,把要的那几位提出来丢线性基里,异或出0的方案数就是$2^{S-cnt}$,$cnt$是线性基的大小。

 1 //#include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<math.h>
 5 //#include<time.h>
 6 //#include<complex>
 7 //#include<set>
 8 //#include<queue>
 9 #include<algorithm>
10 #include<stdlib.h>
11 using namespace std;
12 
13 #define LL long long
14 int qread()
15 {
16     char c; int s=0; while ((c=getchar())<'0' || c>'9');
17     do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s;
18 }
19 
20 //Pay attention to '-' , LL and double of qread!!!!
21 
22 int n,S;
23 LL ans,f[22],a[66],b[66],two[66]; int list[22][22],len[22],bel[22];
24 
25 struct JI
26 {
27     LL a[66]; int n,m;
28     void clear(int mm) {m=mm; n=0; memset(a,0,sizeof(a));}
29     void insert(LL v)
30     {
31         for (int i=m;~i;i--) if ((v>>i)&1)
32         {
33             if (!a[i]) {a[i]=v; n++; break;}
34             v^=a[i];
35         }
36     }
37 }ji;
38 
39 void calc(int tot)
40 {
41     memset(b,0,sizeof(b));
42     int lb=0;
43     for (int i=1,pp=0;i<=n;i++)
44         for (int j=i+1;j<=n;j++,pp++)
45             if (bel[i]!=bel[j])
46             {
47                 for (int k=1;k<=S;k++) b[k]|=((a[k]>>pp)&1)<<lb;
48                 lb++;
49             }
50     ji.clear(lb-1);
51     for (int i=1;i<=S;i++) ji.insert(b[i]);
52     ans+=f[tot]*two[S-ji.n];
53 }
54     
55 void dfs(int cur,int tot)
56 {
57     if (cur>n) {calc(tot); return;}
58     for (int i=1;i<=tot;i++)
59     {
60         bel[cur]=i;
61         list[i][++len[i]]=cur;
62         dfs(cur+1,tot);
63         len[i]--;
64     }
65     bel[cur]=tot+1;
66     list[tot+1][++len[tot+1]]=cur;
67     dfs(cur+1,tot+1);
68     len[tot+1]--;
69 }
70 
71 char s[55];
72 int main()
73 {
74     S=qread();
75     for (int i=1;i<=S;i++)
76     {
77         scanf("%s",s); int m=strlen(s);
78         n=(int)(sqrt(1+8*m)+1.1)>>1;
79         for (int j=0;j<m;j++) a[i]|=(LL)(s[j]=='1')<<j;
80     }
81     
82     {
83         LL fac=1; int fu=1;
84         for (int i=1;i<=n;i++)
85         {
86             f[i]=fac*fu;
87             fu=-fu; fac*=i;
88         }
89         two[0]=1; for (int i=1;i<=S;i++) two[i]=two[i-1]<<1;
90     }
91     
92     ans=0; dfs(1,0);
93     printf("%lld\n",ans);
94     return 0;
95 }
View Code

 

posted @ 2018-04-24 11:36  Blue233333  阅读(421)  评论(0编辑  收藏  举报