CF1326F2 Wise Men (Hard Version)

Wise Men (Hard Version)

\(n\) wise men live in a beautiful city. Some of them know each other.

For each of the n! possible permutations \(p_1, p_2, \ldots, p_n\) of the wise men, let's generate a binary string of length \(n-1\): for each \(1 \leq i < n\) set \(s_i=1\) if \(p_i\) and \(p_{i+1}\) know each other, and \(s_i=0\) otherwise.

For all possible \(2^{n-1}\) binary strings, find the number of permutations that produce this binary string.

\ (2 \ leq n \ leq 18 \) .

answer

For each binary string s, let's calculate \(f(s)\) – the number of permutations, such that, if \(s_i=1\), then \(p_i and p_{i+1}\) know each other, otherwise, they may know or don't know each other.

To get real answers, we may use inclusion-exclusion, which may be optimized using a straightforward sum over subsets dp. 说的就是高维前缀差。

To calculate \(f(s)\), we need to note that \(f\) depends only on the multiset of lengths of blocks of \(1\)'s in it.

For Example, \ (F (110111) = F (111011) \) , Because The multiset of lengths IS \ (\ {. 1,. 3,. 4 \} \) (Note that Block of size \ (X \) of \ ( 1 \) 'corresponds to length S \ (X 1 + \) ). a \ (0 \) also corresponds to a length \ (1 \) block.

And note that there are exactly \(P(n)\) (the number of partitions of \(n\)) possible multisets.

\(P(18) = 385\)

To process further, at first let's calculate \(g(len, mask)\) – the number of paths of length \(len\), which pass only through the vertices from \(mask\) (and only through them).

You can calculate it with a straightforward \(dp(mask, v)\) in \(\mathcal{O}{(2^n \cdot n^2)}\).

Then, let's fix the multiset of lengths \(a_1, a_2, \ldots, a_k\).

I claim that the \(f(s)\) for this multiset is equal to \(\sum{\prod{g(a_i, m_i)}}\) over all masks \(m_1, m_2, \ldots m_k\), such that the bitwise OR of \(m_1, m_2, \ldots, m_k\) is equal to \(2^n-1\) (note that we don't care about the number of bits like in a usual non-intersecting subsets convolution, because if some masks are intersecting, then their OR won't be equal to \(2^n-1\) because \(\sum{a_i} = n\)).

CAN SUM by the Calculate the this by You Changing \ (g (len) \) to at The SUM over Subsets. For \ (g (len) \) to do high-dimensional and prefixes.

And the then, for the this Partition, you CAN Just the Calculate \ (D (mask) \) = \ (\ Prod {G (a_i, mask)} \) in \ (\ mathcal {O} {(K \ CDOT 2 ^ n- )} \) , and you CAN Restore The Real value of \ (2-n-^. 1 \) by-Exclusion Inclusion in \ (\ mathcal {O} {(^ n-2)} \) . note \ (D ( mask) \) statistics program ensures that only after the point is \ (mask \) subset, so should be a mandatory enumeration go the inclusion and exclusion of those points.

IF you Will the Calculate the this naively, you Will GET The \ (\ mathcal {O} ((\ text {SUM of sizes of All Partitions}) \ CDOT 2 ^ n-) \) Solution, Which IS enough to GET the AC. If you enumerate the division after the violence operator \ (d (mask) \) , then is this complexity.

But you CAN Optimize the this Because you CAN Maintain \ (D (mask) \) During The Brute Force of All Partitions. And in The Tree of All Partitions, there are \ (\ mathcal {O} {(P (n-))} \) Intermediate the vertices, SO IT Will Work in \ (\ mathcal {O} {(P (n-) \ CDOT 2 ^ n-)} \) . in the process of DFS in the way maintenance click \ (d (mask) \) is this complexity.

The total complexity is \(\mathcal{O}{((P(n) + n^2) \cdot 2^n))}\).

CO int N=18;
int e[N];
int64 dp[1<<N][N],g[N+1][1<<N];
int64 d[1<<N],cur[N+1][1<<N];
int64 f[1<<N];

int main(){
    int n=read<int>();
    for(int i=0;i<n;++i){
        static char s[N];scanf("%s",s);
        for(int j=0;j<n;++j)if(s[j]=='1') e[i]|=1<<j;
    }
    for(int i=0;i<n;++i) dp[1<<i][i]=1;
    for(int mask=0;mask<1<<n;++mask)
        for(int i=0;i<n;++i)if(dp[mask][i]){
            for(int j=0;j<n;++j)if(~mask>>j&1 and e[i]>>j&1)
                dp[mask|1<<j][j]+=dp[mask][i];
            g[popcount(mask)][mask]+=dp[mask][i];
        }
    for(int len=1;len<=n;++len){
        for(int i=0;i<n;++i)
            for(int mask=0;mask<1<<n;++mask)if(mask>>i&1)
                g[len][mask]+=g[len][mask^1<<i];
    }
    map<vector<int>,vector<int> > ok;
    for(int mask=0;mask<1<<(n-1);++mask){
        int x=0;
        vector<int> t;
        for(;x<n;++x){
            int len=1;
            while(mask>>x&1) ++x,++len;
            t.push_back(len);
        }
        sort(t.begin(),t.end());
        ok[t].push_back(mask);
    }
    vector<int> a;
    for(int mask=0;mask<1<<n;++mask) d[mask]=1;
    function<void(int,int)> dfs=[&](int s,int last){ // sum len, last len
        if(s==n){
            int64 res=0;
            int x=(1<<n)-1;
            for(int mask=0;mask<1<<n;++mask){
                if(popcount(mask)%2==0) res+=d[x^mask];
                else res-=d[x^mask];
            }
            for(int c:ok[a]) f[c]+=res;
            return;
        }
        if(s+last>n) return;
        for(int mask=0;mask<1<<n;++mask) cur[s][mask]=d[mask];
        for(int i=last;s+i<=n;++i){ // current len >= last len
            if(s+i!=n and s+2*i>n) continue;
            a.push_back(i);
            for(int mask=0;mask<1<<n;++mask) d[mask]*=g[i][mask];
            dfs(s+i,i);
            for(int mask=0;mask<(1<<n);++mask) d[mask]=cur[s][mask];
            a.pop_back();
        }
    };
    dfs(0,1);
    for(int i=0;i<n-1;++i)
        for(int mask=0;mask<1<<(n-1);++mask)if(~mask>>i&1)
            f[mask]-=f[mask|1<<i];
    for(int mask=0;mask<1<<(n-1);++mask)
        printf("%lld%c",f[mask]," \n"[mask==(1<<(n-1))-1]);
    return 0;
}

Guess you like

Origin www.cnblogs.com/autoint/p/12544403.html