首页 > 其他分享 >「KDOI-06-S」题解

「KDOI-06-S」题解

时间:2024-09-15 14:13:03浏览次数:8  
标签:dots 连通 ch 06 割边 题解 KDOI times 位为

T2 树上异或

题面

分析

树形 DP 题

考虑一颗子树内部的某种割边方式,假设其被分为 \(n\) 个连通块,每个连通块的权值分别为 \(a_1, a_2, \dots, a_n\),那么该子树在这种割边方式下对答案的贡献就为 \(\prod_{i = 1}^{n} a_i\)。

因此就可以从叶子向根不断合并,求出每种割边状态的值,时间复杂度为 \(O(2^{n - 1}n)\),期望得分 \(8\) 分。

这启示往树形 DP 的方向思考。

将每次定下割边的方法转变,考虑在 DP 过程中通过将两个连通块连接到一起,去遍历每一种状态。

这样,每回溯到一个点:

  1. 遍历该点的子树
  2. 把与该点之间存在割边的连通块与该点之前所找到的连通块合并
  3. 每次合并后求出该情况的贡献(如图,将蓝色连通块的权值异或在一起,然后计算结果)

实现困难,时间复杂度极高。

因为连通块对答案的贡献是 \(\prod_{i = 1} ^{n} a_i\) 的形式,故某子树除去被合并的连通块后不同情况产生的贡献是可以累加的。(答案是 \(a_1 b_1+\dots+a_1 b_n+a_2 b_1+\dots+a_n b_n\),即 \((a_1+\dots+a_n)(b_1+\dots+b_n)\))。

而合并连通块却无法这样优化。

对此,有一种方法能够快速地合并连通块——拆位。

具体来说,定义 \(f_{u, i, j}\) 表示以 \(u\) 所在的连通块的权值第 \(i\) 位为 \(j\) 时以 \(u\) 为根节点的子树除了\(u\) 所在的连通块其他连通块的乘积的值,定义 \(g_u\) 表示以 \(u\) 为根节点的子树对答案的贡献。

容易得到:$$g_u = \sum_{i = 0}^{63}f_{u, i, 1} \times 2^i$$,即 \(u\) 所在连通块第 \(i\) 位为 \(1\) 时,所有的割边方案的贡献。

故仅需考虑 \(f_{u, i, j}\) 的转移。

考虑当前遍历到 \(u\) 的儿子节点 \(v\),则:

  1. 如果不合并,则 \(v\) 的子树全都与 \(u\) 所在的连通块无关,那么 \(g_v\) 全都要乘到 \(f_{u, i, 0}\)。
  2. 合并第 \(i\) 位为 \(1\) 的情况,如果连通块原本为 \(1\) ,则与该子树中第 \(i\) 位为 \(0\) 的异或后第 \(i\) 位仍然为 \(1\)。否则为与第 \(i\) 位为 \(1\) 的连通块异或。
  3. 第 \(i\) 位为 \(0\) 则恰好相反。

即:

\[f_{u, i, 0} = f_{u, i, 0} \times g_{v} + f_{v, i, 0} \times f_{u, i, 0} + f_{v, i, 1} \times f_{u, i, 1} \]

\[f_{u, i, 1} = f_{u, i, 1} \times g_v + f_{v, i, 0} \times f_{u, i, 1} + f_{v, i, 1} \times f_{u, i, 0} \]

答案为 \(g_1\)。

注意

本题空间较小,动态规划数组开 long long 会爆。

点击查看代码
/*
  --------------------------------
  |        code by FRZ_29        |
  |          code  time          |
  |          2024/09/15          |
  |           13:42:20           |
  |             星期天            |
  --------------------------------
                                  */

#include <iostream>
#include <climits>
#include <cstdio>
#include <ctime>
typedef long long LL;

using namespace std;

void RD() {}
template<typename T, typename... U> void RD(T &x, U&... arg) {
    x = 0; int f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    x *= f; RD(arg...);
}

const int N = 5e5 + 5;
const int mod = 998244353;

#define PRINT(x) cout << #x << "=" << x << "\n"
#define LF(i, __l, __r) for (int i = __l; i <= __r; i++)
#define RF(i, __r, __l) for (int i = __r; i >= __l; i--)

int head[N], Next[N << 1], ver[N << 1], tot = 1;
int n, f[N][65][2], g[N];
LL a[N];

void add(int u, int v) {
    ver[++tot] = v;
    Next[tot] = head[u], head[u] = tot;
}

void dfs(int u, int _f) {
    LF(i, 0, 63) f[u][i][a[u] >> i & 1] = 1;
    
    for (int i = head[u]; i; i = Next[i]) {
        int v = ver[i];
        if (v == _f) continue;
        dfs(v, u);

        LF(i, 0, 63) {
            LL t0 = f[u][i][0], t1 = f[u][i][1];
            f[u][i][0] = (t0 * g[v] + t0 * f[v][i][0] + t1 * f[v][i][1]) % mod;
            f[u][i][1] = (t1 * g[v] + t1 * f[v][i][0] + t0 * f[v][i][1]) % mod;
        }
    }

    LF(i, 0, 63) g[u] = (g[u] + (1LL << i) % mod * f[u][i][1]) % mod;
}

int main() {
//    freopen("read.in", "r", stdin);
//    freopen("out.out", "w", stdout);
//    time_t st = clock();
    RD(n);
    LF(i, 1, n) RD(a[i]);
    LF(u, 2, n) {
        int v; RD(v);
        add(u, v), add(v, u);
    }
    dfs(1, 0);
    printf("%d", g[1]);
//    printf("\n%dms", clock() - st);
    return 0;
}

/* ps:FRZ弱爆了 */

标签:dots,连通,ch,06,割边,题解,KDOI,times,位为
From: https://www.cnblogs.com/FRZ29/p/18415215

相关文章

  • 【洛谷 P1596】[USACO10OCT] Lake Counting S 题解(深度优先搜索)
    [USACO10OCT]LakeCountingS题面翻译由于近期的降雨,雨水汇集在农民约翰的田地不同的地方。我们用一个的网格图表示。每个网格中有水(W)或是旱地(.)。一个网格与其周围的八个网格相连,而一组相连的网格视为一个水坑。约翰想弄清楚他的田地已经形成了多少水坑。给出约翰田地的示意图,......
  • 2024-06-02 矩阵重塑2
    include<bits/stdc++.h>usingnamespacestd;constintmaxn=1e4+1;intmar[maxn];voidtmar(intmar[],constintn,constintm){intmat[n+1][m+1],mat1[m+1][n+1];inti,j;for(i=1;i<=n;i++){for(j=1;j<=m;j++){mat[i][j]=mar[(i-1)*m+j];}}for(......
  • 洛谷P1006
    题目传送门:传送门p1006题目描述小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题。一次素质拓展活动中,班上同学安排坐成一个 mm 行 nn 列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了。幸运的是,他们可以通过传纸条来进行交流。纸条要......
  • Codeforces Round 972 (Div. 2) 2005C. Lazy Narek 题解
    原题链接:https://codeforces.com/contest/2005/problem/C看了教程发现都是用dp做的,在这里分享一个差不多的SPFA的思路(赛场上忘了Dijkstra不能有负边所以炸了)时间复杂度与dp同样是O(nm)形式化题意和翻译:有n个长度为m的字符串,你可以选择或不选择来拼接它们,但是不能更改字符串的......
  • 食物链题解
    双倍经验:P2024[NOI2001]食物链当问题要求维护一些对立的关系时(朋友、敌人),就可以用种类并查集实现。因为有三种关系所以并查集的数组要开三倍空间,第一倍空间存同类关系,第二倍存捕食关系,第三倍存被捕食关系。注意:一的猎物的猎物就是一的天敌,其他就可以直接并查集维护即可。注......
  • [ABC371D] 1D Country 题解
    这题,怎么说呢,\(STL\)大法好。前置芝士:lower_pound函数在结构体上的使用。那其实这题便是一个二分前缀和的水题了。结构体存储每个村庄的距离\(x\),人口\(d\)。对于每个输入的\([l,r]\)二分查找其对应的村庄,进行一次答案的统计,输出即可。代码:#include<bits/stdc++.......
  • D06【python接口自动化学习】-python基础
    day06注释学习日期:20240913学习目标:注释:如何写程序的说明书?学习笔记:1.1 如何编写注释注释的位置注释写在代码上面,是最常用的形式注释写在代码前面,常用于代码调试注释的内容怎么写注释要解释代码是做什么,以下建议注释2,不采用注释1python之禅总结注释......
  • 【LGR-200-Div.4】洛谷入门赛 #27 A-H题解
    A#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;mt19937rnd(time(0));#defineintlonglongtypedeftuple<int,int,int>tp;#definexfirst#defineysecondtypedefpair<int,int>pii;typedefpair<double,double>......
  • 题解 [ABC371G] Lexicographically Smallest Permutation(中文/English)
    本题解提供英文版,位于示例代码之后。Englishversionofthiseditorialisprovidedafterthesamplecode.官方题解竟然用Python来算高精度lcm,我来提供一个可以避免一切大整数运算的方法。考察\(u\getsP_u\)这张图的每个置换环。为了使答案字典序最小,显然需要从前往后......
  • 2024年06月中国电子学会青少年软件编程(图形化)等级考试试卷(四级)答案 + 解析
    青少年软件编程(图形化)等级考试试卷(四级)分数:100题数:24一、单选题(共10题,共30分)1.运行下列程序,输入单词“PLAY”,最后角色说?()A.LY4APB.AP4LYC.YA4PLD.PL4AY正确答案:B答案解析:根据程序分析可知,首先获取单词字符数,然后奇数位的字母放在字符数左侧,......