2019 沈阳网络赛 D Fish eating fruit ( 树形DP)

题目传送门

题意:求一颗树中所有点对(a,b)的路径长度,路径长度按照模3之后的值进行分类,最后分别求每一类的和

分析:树形DP

\(dp[i][j]\) 表示以 i 为根的子树中,所有子节点到 i 的路径长度模3等于 j 的路径之和
\(c[i][j]\) 表示以 i 为根的子树中,所有子节点到 i 的路径长度模3等于 j 的点数
\(ok[i][j]\) 表示以 i 为根的子树中,是否有子节点到 i 的路径长度模3等于 j

每次只考虑所有经过根 x 的路径,并且路径的一个端点在 x 的一颗子树上,另一个端点在 x 的另一颗子树上。(可以想到其他所有情况都可以在考虑 x 的子树结点或者是x的祖先结点时被考虑到)
假设当前枚举到 x 的子节点 y,之前遍历的子节点已经使得三个数组更新。那么我们假设要计算的路径的起点在 y ,要计算的路径的终点在之前遍历过的子节点中。

计算答案贡献:
关于x-y的连边的贡献为
\(c[x][a] * c[y][b] * edge\)
关于起点到 y 的所有路径长度的贡献为
\(c[x][a] * dp[y][b]\)
关于x到终点的所有路径长度的贡献为
\(c[y][b] * dp[x][a]\)

最终边权所属分类为\((a+b+edge) \% 3\) 累加到答案即可

关于更新 x
用 y 来更新 x
\(dp[x][(a+edge)\%3] += dp[y][a] + edge * c[y][a]\)
\(ok[x][(a+edge)\%3] = true\)
\(c[x][(a+edge)\%3] += c[y][a]\)

当然点分治也可以做,但是复杂度就不是很优秀了

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 10010;
const int M = 200010;
const ll mod = 1e9 + 7;
int head[N],ver[M],nxt[M],tot;
int x,y,n;
bool ok[N][3];
ll edge[M],z,dp[N][3],c[N][3];
ll ans[3];
void add(int x,int y,ll z){
    ver[++tot] = y;edge[tot] = z;nxt[tot] = head[x];head[x] = tot;
}
void dfs(int x,int fa){
    for(int i=head[x];i;i=nxt[i]){
        int y = ver[i];
        if(y == fa)continue;
        dfs(y,x);
        ll z = edge[i];
        for(int j=0;j<3;j++){
            for(int k=0;k<3;k++){
                if(ok[x][j] && ok[y][k]){
                    ans[(j+k+z)%3] += (dp[x][j] * c[y][k]% mod + dp[y][k] * c[x][j] % mod) % mod;
                    ans[(j+k+z) % 3] += z * c[x][j] * c[y][k] % mod;
                    ans[(j+k+z)%3] %= mod;
                }
            }
        }
        for(int j=0;j<3;j++){
            if(ok[y][j]){
                dp[x][(j+z) % 3] += dp[y][j] + z * c[y][j] % mod;
                dp[x][(j+z) % 3] %= mod;
                c[x][(j+z)%3] += c[y][j];
                ok[x][(j+z) % 3] = true;
            }
        }
    }
}
int main(){
    while(~scanf("%d",&n)){
        ans[0] = ans[1] = ans[2] = 0;
        tot = 0;
        for(int i=1;i<=n;i++){
            dp[i][0] = dp[i][1] = dp[i][2] = 0;
            c[i][1] = c[i][2] = 0;
            c[i][0] = 1;
            ok[i][0] = true;
            ok[i][1] = ok[i][2] = false;
            head[i] = 0;
        }
        for(int i=1;i<n;i++){
            scanf("%d%d%lld",&x,&y,&z);
            x ++;
            y ++;
            add(x,y,z);
            add(y,x,z);
        }
        dfs(1,0);
        printf("%lld %lld %lld\n",ans[0] * 2 % mod,ans[1] * 2 % mod,ans[2] * 2 % mod);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/1625--H/p/11521171.html

时间: 2024-08-19 14:14:33

2019 沈阳网络赛 D Fish eating fruit ( 树形DP)的相关文章

Fish eating fruit 沈阳网络赛(树形dp)

Fish eating fruit \[ Time Limit: 1000 ms \quad Memory Limit: 262144 kB \] 题意 大体的题意就是给出一棵树,求每一对点之间的距离,然后把该距离存在距离 \(\mod 3\) 的位置,输出总和. 思路 令两个 \(dp\) 数组和两个辅助 \(dp\) 的数组. \(dp1[i][j]\) 表示从 \(i\) 为起点往下到各个点距离 \(\mod 3\) 后为 \(j\) 的距离总和. \(cnt1[i][j]\) 表示以 \

2015沈阳网络赛1003 Minimum Cut 树链剖分 数组维护前缀和进行区间增减

2015沈阳网络赛1003  Minimum Cut   树链剖分 数组维护前缀和进行区间增减 Minimum Cut Time Limit: 3000/2000 MS (Java/Others)    Memory Limit: 65535/102400 K (Java/Others)Total Submission(s): 0    Accepted Submission(s): 0 Problem Description Given a simple unweighted graph G 

2019徐州网络赛 XKC&#39;s basketball team 线段树

网址:https://nanti.jisuanke.com/t/41387 题意: 大家好,我是训练时长两年半的个人练习生蔡徐坤,我的爱好是唱,跳,rap,篮球. 给出一段长度为$n,(n \leq 1e5)$的序列,对每一个数,求出它和它后面比它大$m$的数中间夹着的数的数量,没有输出$-1$. 题解: 直接建线段树,维护最大值,然后查询时对第$i$个数,搜索区间$[i,n]$之中大于$num[i]+m$的值的位置的最大值,具体操作是先限定区间,然后求出所有合法位置,取最大值,如果搜索不到则返

ACM-ICPC 2019南昌网络赛I题 Yukino With Subinterval

ACM-ICPC 2019南昌网络赛I题 Yukino With Subinterval 题目大意:给一个长度为n,值域为[1, n]的序列{a},要求支持m次操作: 单点修改 1 pos val 询问子区间中某个值域的数的个数,连续的相同数字只记为一个.(即统计数字段的个数) 2 L R x y 数据范围: 1 ≤ n,m ≤ 2×10^5 1 ≤ a[i] ≤ n 解题思路: 连续重复的数字只记一次.所以考虑将每个数字段除第一个出现外的数字都删去(记为0).在读入操作的时候暴力模拟,同时维护

2019ACM-ICPC沈阳网络赛-C-Dawn-K&#39;s water(完全背包模板题)

Dawn-K's water  1000ms 262144K Dawn-K recently discovered a very magical phenomenon in the supermarket of Northeastern University: The large package is not necessarily more expensive than the small package. On this day, Dawn-K came to the supermarket

2019ACM-ICPC沈阳网络赛-K-Guanguan&#39;s Happy water(思维+暴力)

Guanguan's Happy water 4000ms 262144K Rather than drinking happy water, Guanguan loves storing happy water. So he bought a refrigerator and stored a_iai? bottles of cola into it every day. When the storage is finished on the kk-th day, the refrigerat

2015长春、沈阳网络赛总结

我所说的总结并不是谈什么题目解法之类的东西 这些东西网上有很多题解 说说这两场网赛吧! 这两场我的状态还行,只是xiaodong还没有找到状态,长春赛lucas+中国剩余定理他硬是打了一整场,还是没打出来,版题没打出来确实不该 wzb状态一般,不过看题的能力依然那么厉害 长春赛中,很遗憾的只出了5道题,按当时过题数目,应该是7道德,可是小东的lucas那题没打出来,而我打得后缀数组那题,当顺时针的时候不用看是否是下标最前面的,但是反过来就需要看了,当时想当然的认为不用,交了4发,一直wa到比赛结

2019 CCPC网络赛

一到网络赛,大家都是东亚之光 1001 00:23:46 solved by hl 签到 枚举一下位就行了 #include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <bitset

南昌邀请赛网络赛 D.Match Stick Game(dp)

南昌邀请赛网络赛 D.Match Stick Game 题目传送门 题目就会给你一个长度为n的字符串,其中\(1<n<100\).这个字符串是一个表达式,只有加减运算符,然后输入的每一个字符都是可以由若干个火柴棒拼接而成的. 现在在不改变每个数的位数,数的总数以及运算符的个数的前提下,可以对火柴棒重新拼接.询问最后可以拼接出来的最大值是多少. 这个自己看下题目可能要清楚一些= = ? 每一个字符都是由若干个火柴棒构成的,我们可以考虑类似于背包的思路来求解. 因为每个数的位数最后都没发生变化,所