【XSY2701】異或圖 線性基 容斥原理
阿新 • • 發佈:2018-03-06
post line %d 每一個 題目 spa sca type 而在
題目描述
定義兩個圖\(G_1\)與\(G_2\)的異或圖為一個圖\(G\),其中圖\(G\)的每條邊在\(G_1\)與\(G_2\)中出現次數和為\(1\)。
給你\(m\)個圖,問你這\(m\)個圖組成的集合有多少個子集的異或圖為一個連通圖。
\(n\leq 10,m\leq 60\)
題解
考慮枚舉圖的子集劃分,讓被劃分到不同子集的點之間沒有連邊,而在同一個子集裏面的點可以連通,可以不連通。
可以用高斯消元(線性基)得到滿足條件的圖的個數。設枚舉的子集劃分有\(k\)個集合,那麽容斥系數就是\({(-1)}^{k-1}(k-1)!\)。並把當前的方案數乘以容斥系數計入答案。
那麽容斥系數是怎麽來的呢?
記\(c_i\)為\(i\)個集合的容斥系數。對於每一個聯通塊個數為\(j\)的圖,對枚舉到的聯通塊個數為\(i\)的方案有\(S(j,i)\)的貢獻。
我們只需要讓\(\sum_{i=m}^nc(i)S(i,m)=[m=1]\)就可以了。
可以打表消元消除容斥系數。
時間復雜度:\(O(B_nn^2m)\),其中\(B_n\)是Bell數的第\(n\)項。
代碼
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
char s[1010];
int n,m;
ull a[20][20];
int d[20];
ull ans=0;
ull pw[70];
ull fac[70];
ull c[70];
void dfs(int x,int y)
{
if(x>n)
{
int i,j,k;
for(i=0;i<m;i++)
c[i]=0;
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)
if (d[i]!=d[j])
{
ll s=a[i][j];
for(k=m-1;k>=0;k--)
if(s&(1ll<<k))
{
if(!c[k])
{
c[k]=s;
break;
}
s^=c[k];
}
}
int num=0;
for(i=0;i<m;i++)
if(!c[i])
num++;
ans+=pw[num]*fac[y-1]*(y&1?1:-1);
return;
}
int i;
for(i=1;i<=y;i++)
{
d[x]=i;
dfs(x+1,y);
}
d[x]=y+1;
dfs(x+1,y+1);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
scanf("%d",&m);
int i,j,k;
int len;
fac[0]=1;
pw[0]=1;
for(i=1;i<=m;i++)
pw[i]=pw[i-1]<<1;
for(i=1;i<=m;i++)
{
scanf("%s",s+1);
if(i==1)
{
len=strlen(s+1);
for(j=2;j<=10;j++)
if(j*(j-1)/2==len)
break;
n=j;
}
int t=0;
for(j=1;j<=n;j++)
for(k=j+1;k<=n;k++)
if(s[++t]=='1')
a[j][k]|=1ll<<(i-1);
}
for(i=1;i<=n;i++)
fac[i]=fac[i-1]*i;
dfs(1,0);
printf("%llu\n",ans);
return 0;
}
【XSY2701】異或圖 線性基 容斥原理