【BZOJ4671】(斯特林反演)

題目

【BZOJ4671】異或圖
頗有意思的題php

作法

直接處理顯然很難,咱們考慮範圍擴大以求容斥或反演這類的幫助c++

\(f_i\)表示至少有\(i\)個聯通塊的方案,形如設立\(i\)個聯通塊輪廓,聯通塊內連邊隨意,聯通塊與聯通塊之間無連邊spa

\(g_i\)表示剛好有\(i\)個聯通塊的方案,形如設立\(i\)個聯通塊輪廓,在保證內部聯通的狀況下,外部塊與塊間無連邊code

顯然:\[f_x=\sum\limits_{i=x}^n\begin{Bmatrix}i\\x\end{Bmatrix}g_i\]get

根據斯特林反演:\[g_x=\sum\limits_{i=x}^n (-1)^{i-x}\begin{bmatrix}i\\x\end{bmatrix}f_i\]it

\(g_1=\sum\limits_{i=1}^n (-1)^{i-1}\begin{bmatrix}i\\1\end{bmatrix}f_i\)class

\(\begin{bmatrix}i\\1\end{bmatrix}\)是階乘形式:\(\begin{bmatrix}i\\1\end{bmatrix}=(i-1)!\)im

化簡答案爲:\(g_1=\sum\limits_{i=1}^n (-1)^{i-1}(i-1)!f_i\)di

考慮\(f_i\)如何求出:狀壓點所屬聯通塊狀態,則咱們要選擇圖集使塊與塊之間無邊,考慮枚舉每一個圖的\(S\)表示點與點之間的連邊(不屬同一聯通塊),咱們壓到線性基裏去,\(ele\)表示線性基元素,這些元素是不能選擇的(相異),故答案爲\(2^{N-ele}\)co

Code

#include<bits/stdc++.h>
typedef int LL;
const LL maxn=109;
LL N,n;
LL G[maxn][maxn][maxn],a[maxn];
char s[maxn];
long long ans,p[maxn],S,fac[15];
void Dfs(LL x,LL up){
    if(x==n+1){
        memset(p,0,sizeof(p)); LL ele(0);
        for(LL i=1;i<=N;++i){
            S=0; LL tot(0);
            for(LL j=1;j<=n;++j)
                for(LL k=j+1;k<=n;++k)
                    if(a[k]!=a[j]){
                        S|=(1ll<<tot)*G[i][j][k];
                        ++tot;
                    }
            for(LL j=0;j<tot;++j){
                if(S&(1ll<<j)){
                    if(!p[j]){
                        p[j]=S;
                        ++ele;
                        break;
                    }else 
                        S^=p[j];
                }
            }
        }
        ans+=1ll*((up&1)?1:-1)*fac[up-1]*(1ll<<N-ele);
        return;
    }
    for(LL i=1;i<=up+1;++i){
        a[x]=i;
        Dfs(x+1,std::max(up,i));
    }
}
int main(){
    scanf("%d",&N);
    for(LL i=1;i<=N;++i){
        scanf(" %s",s+1);
        LL len(strlen(s+1));
        if(!n){
            n=1;
            for(;n*(n-1)/2!=len;++n);
        }
        LL now(0);
        for(LL j=1;j<=n;++j) for(LL k=j+1;k<=n;++k) G[i][j][k]=s[++now]-'0';
    }
    fac[0]=fac[1]=1; for(LL i=2;i<=n;++i) fac[i]=fac[i-1]*i;
    Dfs(1,0);
    printf("%lld",ans);
    return 0;
}
相關文章
相關標籤/搜索