cf1101 D. GCD Counting(树形dp)
题意:
在树中找一条最长的链,链上所有点的点权的gcd大于1。
思路:
每个数的质因子数量是非常少的,可以认为是个位数。因为2×3×5一直乘到19就快1e7了。
\(p[u][j]\) 为编号为 \(u\) 的节点的第 \(j\) 个质因子
\(dp[u][i]\) 表示以 \(u\) 为一个端点,\(u\) 的子树中的某点为另一端点的最长链的长度,且链上所有点都有质因子 \(p[u][i]\) 。dfs暴力找父子节点有无共同质因子,记录子节点的最大值和次大值,更新答案。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 5;
int n;
vector<int> G[N];
vector<int> p[N]; // p[i]表示a[i]的所有质因子
int dp[N][13], ans;
void dfs(int u, int fa) {
    for (int i = 0; i < (int)p[u].size(); ++i) {
        dp[u][i] = 1;
    }
    for (int v : G[u]) if (v != fa) {
        dfs(v, u);
        for (int i = 0; i < (int)p[u].size(); ++i) {
            for (int j = 0; j < (int)p[v].size(); ++j) {
                if (p[u][i] == p[v][j]) {
                    ans = max(ans, dp[u][i] + dp[v][j]);
                    dp[u][i] = max(dp[u][i], dp[v][j] + 1);
                }
            }
        }
    }
}
int minp[N], pri[N], pcnt;
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    // 线性筛预处理每个数的最小质因子,加速分解质因数,要不然会超时
    for (int i = 2; i < N; ++i) {
        if (!minp[i]) minp[i] = i, pri[++pcnt] = i;
        for (int j = 1; i * pri[j] < N; ++j) {
            minp[i * pri[j]] = pri[j];
            if (minp[i] == pri[j]) break;
        }
    }
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        int ai;
        cin >> ai;
        if (ai > 1) ans = 1; // 如果ai全是1的话答案就是0
        while (ai > 1) {
            int d = minp[ai];
            p[i].push_back(d);
            while (ai % d == 0) ai /= d;
        }
    }
    for (int i = 1; i < n; ++i) {
        int x, y;
        cin >> x >> y;
        G[x].push_back(y);
        G[y].push_back(x);
    }
    dfs(1, 0);
    cout << ans;
    return 0;
}
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号