Codeforces #430 Div2 C

#430 Div2 C

题意

给出一棵带点权的树,每一个节点的答案为从当前节点到根节点路径上所有节点权值的最大公因子(在求最大共因子的时候可以选择把这条路径上的任意一点的权值置为0)。对于每一个节点单独考虑,输出最大的答案。

分析

本以为是一道树形DP,写完就 WA 了。
补题的时候呢时间复杂度很迷,写完就 T 了。
一直想着这道题可以抢救一下,还好没看题解,其实只要想想 gcd 的下降速度是很快的,然后就可以乱搞了。

在搜索的时候记录下前面是否把某个权值当做0来算了,分情况讨论下即可。

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 100;
struct Edge {
    int to, nxt;
}e[MAXN << 1];
int head[MAXN], cnt = 0;
void add(int u, int v) {
    e[cnt].to = v;
    e[cnt].nxt = head[u];
    head[u] = cnt++;
}
int a[MAXN], dp[MAXN];

int gcd(int a, int b) {
    return !b ? a : gcd(b, a % b);
}

void dfs(int fa, int u, int fac, int is) {
    if(fac == 1) return;
    dp[u] = max(dp[u], fac);
    for(int i = head[u]; ~i; i = e[i].nxt) {
        int v = e[i].to;
        if(v != fa) {
            int gcd_ = gcd(fac, a[v]);
            if(is && gcd_ > 1) {
                dfs(u, v, gcd_, 1);
            } else if(!is) {
                if(gcd_ < fac) {
                    if(gcd_ > 1) dfs(u, v, gcd_, 0); // 看似很暴力,但是注意到 gcd 的下降速度是很快的,且保证了 gcd_ < fac 。
                    dfs(u, v, fac, 1);
                }
                else dfs(u, v, fac, 0);
            }
        }
    }
}
//适用于正整数
template <class T>
inline void scan_d(T &ret) {
    char c; ret=0;
    while((c=getchar())<'0'||c>'9');
    while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();
}
int main() {
    memset(head, -1, sizeof head);
    int n;
    scan_d(n);
    for(int i = 1; i <= n; i++) {
        scan_d(a[i]);
        dp[i] = 1;
    }
    for(int i = 1; i < n; i++) {
        int u, v;
        scan_d(u); scan_d(v);
        add(u, v);
        add(v, u);
    }
    dfs(0, 1, 0, 1);
    dfs(0, 1, a[1], 0);
    for(int i = 1; i <= n; i++) {
        printf("%d%c", dp[i], " 
"[i == n]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ftae/p/7454843.html