P5538【XR-3】与运算 + DFS

题意

传送门 P5538【XR-3】Namid[A]me

题解

与运算同时出现在底数与指数,难以处理和式。
∑ 1 ≤ u ≤ v ≤ n f ( u , v ) f ( u , v ) \sum_{1\leq u\leq v\leq n}f(u,v)^{f(u,v)} 1uvnf(u,v)f(u,v) 考虑直接求解 f ( u , v ) f(u,v) f(u,v) 后求和。限制 N D ≤ 3 × 1 0 6 ND\leq3\times 10^6 ND3×106 指出,当点数很大时,树上与子节点连边数大于 1 1 1 的节点数很少。先考虑链上的情况,根据与运算的性质,当 u u u 不变时, f ( u , v ) f(u,v) f(u,v) 的取值只有 O ( log ⁡ A u ) O(\log A_u) O(logAu) 种可能,取值的变化仅发生在 A u A_u Au 的二进制表示中为 1 1 1 的位变为 0 0 0 的情况下。同理,对于以 u u u 为根的子树,对任一子树中的节点 v v v,有 f ( u , v ) f(u,v) f(u,v) 取值只有 O ( log ⁡ A u ) O(\log A_u) O(logAu) 种可能性,那么可以进行哈希。

M = ⌊ log ⁡ 2 A ⌋ + 1 M=\lfloor\log_2A\rfloor+1 M=log2A+1。基于 s t d : : m a p std::map std::map 的树上哈希递推,时间复杂度 O ( N M log ⁡ M ) O(NM\log M) O(NMlogM)。任一对节点 ( u , v ) (u,v) (u,v) f ( u , v ) f(u,v) f(u,v),仅在 l c a ( u , v ) lca(u,v) lca(u,v) 处统计一次,时间复杂度为 O ( min ⁡ ( D 2 M 2 , N 2 ) ) O(\min(D^2M^2,N^2)) O(min(D2M2,N2))
min ⁡ ( D 2 M 2 , N 2 ) ≤ D 2 M 2 + N 2 ≤ 2 N M D \min(D^2M^2,N^2)\leq D^2M^2+N^2\leq 2NMD min(D2M2,N2)D2M2+N22NMD 那么总时间复杂度为 O ( N M ( D + log ⁡ M ) ) O(NM(D+\log M)) O(NM(D+logM)),暴力求解即可。

#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l, _ = r; i < _; ++i)
#define ft first
#define sd second
typedef long long ll;
const int maxn = 200005, _p = 786433, _g = 10;
int N, Res, A[maxn], ind[_p], gPw[_p];
vector<int> G[maxn];
map<int, int> mp[maxn];

void add(int x, int d)
{
    
    
    if (x % _p == 0)
        return;
    int y = gPw[(ll)ind[x % _p] * x % (_p - 1)];
    Res = (Res + (ll)y * d % _p) % _p;
}

void dfs(int u, int p)
{
    
    
    add(A[u], 1);
    ++mp[u][A[u]];
    for (auto &v : G[u])
        if (v != p)
        {
    
    
            dfs(v, u);
            for (auto &x : mp[v])
                for (auto &y : mp[u])
                    add(x.ft & y.ft, (ll)x.sd * y.sd % _p);
            for (auto &x : mp[v])
                mp[u][x.ft & A[u]] += x.sd;
            mp[v].clear();
        }
}

int main()
{
    
    
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    for (int i = 0, x = 1; i < _p - 1; ++i)
        ind[x] = i, gPw[i] = x, x = (ll)x * _g % _p;
    cin >> N;
    rep(i, 0, N) cin >> A[i];
    rep(i, 1, N)
    {
    
    
        int u, v;
        cin >> u >> v;
        --u, --v;
        G[u].push_back(v), G[v].push_back(u);
    }
    dfs(0, -1);
    cout << Res << '\n';
    return 0;
}

おすすめ

転載: blog.csdn.net/neweryyy/article/details/120234290