zoukankan      html  css  js  c++  java
  • bzoj3696 化合物

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3696

    【题解】

    f[x][i]表示x节点子树,值为i的方案数。

    暴力统计理论复杂度$O(nH^2)$。

    按子树排序后统计复杂度好像还是错的。。但是能过

    明天研究FWT。。

    暴力跑了0.8s,FWT跑了3.1s。。。日

    FWT也要按深度合并啊。。FWT的介绍在最后

    # include <stdio.h>
    # include <string.h>
    # include <iostream>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int M = 5e5 + 10, N = 1e5 + 10, H = 512 + 5;
    const int mod = 1e9+7;
    
    int n, f[N][H], g[N], par[N];
    ll ans[H]; 
    
    int t[N], tn;
    inline int cmp(int a, int b) {
        return g[a] < g[b];
    }
    
    int head[N], nxt[N], to[N], tot = 0;
    inline void add(int u, int v) {
        ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v;
    }
    
    ll ss[H], tt[H]; 
    
    inline void FWT(ll *a, int op, int L) {
        if(op) {
            for (int len=2; len<=L; len<<=1) {
                int m = len >> 1;
                for (ll *p = a; p != a+L; p += len) {
                    for (int k=0; k<m; ++k) {
                        ll x = p[k], y = p[k+m];
                        p[k] = (x+y)/2;
                        p[k+m] = (x-y)/2;
                    }
                }
            }
        } else {
            for (int len=2; len<=L; len<<=1) {
                int m = len >> 1;
                for (ll *p = a; p != a+L; p += len) {
                    for (int k=0; k<m; ++k) {
                        ll x = p[k], y = p[k+m];
                        p[k] = x+y;
                        p[k+m] = x-y;
                    }
                }
            }
        }
    }
    
    inline void FWT_combine(int *A, int an, int *B, int bn) {
        int L = 0, m = max(an, bn);
        while((1<<L) < m) ++L; m = (1<<L);
         for (int i=0; i<m; ++i) ss[i] = A[i], tt[i] = B[i];
        FWT(ss, 0, m), FWT(tt, 0, m);
        for (int i=0; i<m; ++i) ss[i] = ss[i] * tt[i];
        FWT(ss, 1, m);
        for (int i=0; i<m; ++i) ans[i] += ss[i];
    }
    
    inline void dfs(int x) {
        int ret = 1;
        f[x][0] = 1; 
        for (int i=head[x]; i; i=nxt[i]) dfs(to[i]);
        tn = 0; for (int i=head[x]; i; i=nxt[i]) t[++tn] = to[i]; 
        sort(t+1, t+tn+1, cmp);
        for (int i=1; i<=tn; ++i) { 
            int h = g[t[i]], y = t[i];
            FWT_combine(f[x], ret, f[t[i]], h);
            for (int j=0; j<h; ++j) f[x][j] += f[y][j];  
            ret = max(ret, h); 
        }
        for (int j=ret; j; --j) f[x][j] = f[x][j-1];
        f[x][0] = 0; 
        g[x] = ret + 1; 
    }
    
    
    int main() {
        cin >> n;
        for (int i=2; i<=n; ++i) scanf("%d", par+i), add(par[i], i); 
        dfs(1);    
        for (int i=511; ~i; --i)
            if(ans[i] != 0) {
                 for (int j=0; j<=i; ++j)
                     printf("%lld
    ", ans[j]);
                return 0;
            }
        return 0;
    }
    View Code

    下面是暴力:

    # include <stdio.h>
    # include <string.h>
    # include <iostream>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int M = 5e5 + 10, N = 1e5 + 10, H = 512 + 5;
    const int mod = 1e9+7;
    
    int n, f[N][H], g[N], par[N];
    ll ans[H]; 
    
    int t[N], tn;
    inline int cmp(int a, int b) {
        return g[a] < g[b];
    }
    
    int head[N], nxt[N], to[N], tot = 0;
    inline void add(int u, int v) {
        ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v;
    }
    
    inline void dfs(int x) {
        int ret = 1;
        f[x][0] = 1; 
        for (int i=head[x]; i; i=nxt[i]) dfs(to[i]);
        tn = 0; for (int i=head[x]; i; i=nxt[i]) t[++tn] = to[i]; 
        sort(t+1, t+tn+1, cmp);
        for (int i=1; i<=tn; ++i) { 
            int h = g[t[i]], y = t[i];
            for (int j=0; j<ret; ++j) 
                for (int k=0; k<h; ++k)
                    ans[j ^ k] += 1ll * f[x][j] * f[y][k];
            for (int j=0; j<h; ++j) f[x][j] += f[y][j];  
            ret = max(ret, h); 
        }
        for (int j=ret; j; --j) f[x][j] = f[x][j-1];
        f[x][0] = 0; 
        g[x] = ret + 1; 
    }
    
    
    int main() {
        cin >> n;
        for (int i=2; i<=n; ++i) scanf("%d", par+i), add(par[i], i); 
        dfs(1);    
        for (int i=511; ~i; --i)
            if(ans[i] != 0) {
                 for (int j=0; j<=i; ++j)
                     printf("%lld
    ", ans[j]);
                return 0;
            }
        return 0;
    }
    View Code

    ===================================分割线==============================

    考虑集合的位运算卷积
    $C_i = sum_{j oplus k = i}A_jB_k$

    每次只需要考虑最高位,事先补齐集合至2的次幂。
    设符号$C = (A, B)$表示$C$由$A$和$B$顺次拼接而成。

    如果只考虑最高位的话,有:
    $ C = A oplus B = (sum_{j oplus k = 0} A_jB_k, sum_{j oplus k = 1} A_jB_k)$
    (这里的0和1是因为值考虑最高位的原因)

    这给了我们一个非常好的分治想法
    假设我们构造出变换$f$以及逆变换$f_T$,满足:
    $f(A)f(B) = f(C)$
    那么我们就用类似于FFT的方法实现即可。

    1. 如果是异或(xor)卷积的话:
    $A_0$和$A_1$是按照$A$的最高位分成的两部分
    $f(A) = (f(A_0) + f(A_1), f(A_0) - f(A_1))$
    $f_T(A) = (f_T(frac{A_0 + A_1}{2}), f_T(frac{A_0 - A_1}{2}))$
    正确性可以用归纳法证明。
    其实只要记住正变换的式子即可,逆变换可以从正变换推导出来。


    2. 如果是与(and)卷积的话
    $f(A) = (f(A_0) + f(A_1), f(A_1))$
    $f_T(A) = (f_T(A_0) - f_T(A_1), f_T(A_1))$

    3. 如果是或(or)卷积的话
    $f(A) = (f(A_0), f(A_1) + f(A_0))$
    $f_T(A) = (f_T(A_0), f_T(A_1) - f_T (A_0))$

  • 相关阅读:
    How to function call using 'this' inside forEach loop
    jquery.validate.unobtrusive not working with dynamic injected elements
    Difference between jQuery.extend and jQuery.fn.extend?
    Methods, Computed, and Watchers in Vue.js
    Caution using watchers for objects in Vue
    How to Watch Deep Data Structures in Vue (Arrays and Objects)
    Page: DOMContentLoaded, load, beforeunload, unload
    linux bridge
    linux bridge
    EVE-NG网卡桥接
  • 原文地址:https://www.cnblogs.com/galaxies/p/bzoj3696.html
Copyright © 2011-2022 走看看