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 }