【每日一题】1月13日最长树链 分解质因数、DFS

最长树链

https://ac.nowcoder.com/acm/problem/13233

题目描述

给你个节点的一棵树,还有每个点的点权值,现在要你选出一条最长的边,保证这条边中全部的点之后的值不等于,也就是存在一个公共的因子全部点都有。

Solution

思路参考喵渺淼妙的死忠粉大佬这是原题解传送门
观察到这个问题,那么我们第一步想想能不能去枚举,根据唯一分解定理,每一个数都可以拆成一堆质因数幂积的形式。那么现在再看给我们的这棵树,如果把他分解质因数之后,那么可以和它构成一条链的节点一定也存在这些质因数中的一个。那么我们就可以使用一个表,保存全部节点的质因子,我们接下来就可以去枚举这些因子了。那么再枚举这些因子的条件后就变成了求最大的连接的链是多长了,对每个有孩子的子树记录下子树最长的单链,找到最长的两个链连接就行。这个走个即可,关键性的时间复杂度还是前面那个分解全部的数的因子条件,可以看到最极端的情况,个数全部都是大素数里面有个素数,并且都是最接近的那个素数,那么还是会死)大概。那就要加上一个特判大素数的地方,(模板)米勒罗宾素数测试官方题解没加探测函数,然后用我自己的板子发现本来不的加了反而飞了。。就参考了一下YangYL°大佬的板子,把他套在分解质因子前面,好在不炸


1/14 数据更新了,好像蜜汁卡死了。。等我再看看什么地方死了,待更新。只有87分。

#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define all(__vv__) (__vv__).begin(), (__vv__).end()
#define endl "\n"
#define pai pair<int, int>
#define ms(__x__,__val__) memset(__x__, __val__, sizeof(__x__))
#define rep(i, sta, en) for(int i=sta; i<=en; ++i)
typedef long long ll; typedef unsigned long long ull; typedef long double ld;
inline ll read() { ll s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar())    s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; }
inline void print(ll x, int op = 10) { if (!x) { putchar('0'); if (op)    putchar(op); return; }    char F[40]; ll tmp = x > 0 ? x : -x;    if (x < 0)putchar('-');    int cnt = 0;    while (tmp > 0) { F[cnt++] = tmp % 10 + '0';        tmp /= 10; }    while (cnt > 0)putchar(F[--cnt]);    if (op)    putchar(op); }
inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
ll qpow(ll a, ll b) { ll ans = 1;    while (b) { if (b & 1)    ans *= a;        b >>= 1;        a *= a; }    return ans; }    ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; }
const int dir[][2] = { {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int N = 32000 + 7; // sqrt(1e9)
const int M = 1e5 + 7;

vector<int>    prime;
int cnt, n, m;
bool vis[M];

void getprime() { // 欧拉筛法求素数表O(n)
    memset(vis, true, sizeof(vis));
    cnt = 0;
    for (int i = 2; i < N; ++i) {
        if (vis[i]) prime.push_back(i), ++cnt;
        for (int j = 0; j < cnt; ++j) {
            if (i * prime[j] >= N) break;
            vis[i * prime[j]] = false;
            if (i % prime[j] == 0) break;
        }
    }
}

/*米勒罗宾素数测试*/
ll A[11] = { 0,2,3,5,7,11,13,17,19,23,61 };
int Miller_Rabin(int x) {//素数探测算法
    int s = 0;
    if (x == 2) return 1;
    if (x % 2 == 0 || x == 1) return 0;
    int p = x - 1;
    while (p % 2 == 0) p /= 2, s++;
    for (int j = 1; j <= 5; j++) {
        long long B = qpow(A[j], p, x);
        for (int i = 1; i <= s; i++) {
            long long K = (B * B) % x;
            if (K == 1ll && B != 1ll && B != x - 1) return 0;//如果二次探测发现这个不是质数
            B = K;
        }
        if (B != 1ll) return 0;
    }
    return 1;//探测正常结束
}

int head[M], tot = 0;//前向星变量
struct Node {
    //int u; //起点
    //int w; //权值
    int v, next;
} edge[M << 1];

void add(int u, int v) {
    tot++;
    //edge[tot].u = u;
    edge[tot].v = v;
    //edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot;
}
unordered_map<int, vector<int>> has;
int w[M], ans = 1;

int dfs(int u, int num) {
    if (w[u] % num != 0)    return 0;
    vis[u] = 1;
    int res = 1;
    int max1 = -1, max2 = -1;
    for (int i = head[u]; i; i = edge[i].next) {
        int v = edge[i].v;
        if (!vis[v]) {
            int tmp = dfs(v, num);
            res = max(res, 1 + tmp);
            if (tmp >= max1)    max2 = max1, max1 = tmp;
            else if (tmp >= max2)    max2 = tmp;
        }
    }
    if (max1 != -1 and max2 != -1)    ans = max(ans, max1 + max2 + 1);
    else if (max1 != -1)    ans = max(ans, max1);
    return res;
}

void solve() {
    getprime();
    n = read();
    rep(i, 1, n - 1) {
        int u = read(), v = read();
        add(u, v); add(v, u);
    }
    for (int i = 1; i <= n; ++i) {
        w[i] = read();
        int tmp = w[i];
        if (Miller_Rabin(tmp)) {
            prime.push_back(tmp), has[tmp].push_back(i), ++cnt; // 大素数
            continue;
        }
        for (int j = 0; j < cnt; ++j) {
            if (tmp == 1)    break;
            if (tmp % prime[j] == 0) {
                has[prime[j]].push_back(i);
                while (tmp % prime[j] == 0)    tmp /= prime[j];
            }
        }
        if (tmp != 1)    prime.push_back(tmp), has[tmp].push_back(i), ++cnt;
    }
    for (auto& it : prime) {
        ms(vis, 0);
        for (auto& pos : has[it])
            if (!vis[pos])    dfs(pos, it);
    }
    print(ans);
}

int main() {
    //int T = read();    while (T--)
    solve();
    return 0;
}
每日一题 文章被收录于专栏

每日一题

全部评论
这个 Miller-Rabin 咋这么眼熟
点赞 回复 分享
发布于 2021-01-13 22:09
dfs那里跑个树形dp就好了.
点赞 回复 分享
发布于 2021-01-13 21:19
...你应该看看我群里发的东西的...我之前写了次假代码后看错题了,这是求最长链,不是求最大子树.我代码更正了. hack数据: 4 1 2 1 3 1 4 2 2 2 2 输出:3
点赞 回复 分享
发布于 2021-01-13 21:19

相关推荐

做个有文化的流氓:不想当将军的士兵不是好士兵
点赞 评论 收藏
分享
头像
10-13 18:10
已编辑
东南大学 C++
。收拾收拾心情下一家吧————————————————10.12更新上面不知道怎么的,每次在手机上编辑都会只有最后一行才会显示。原本不想写凉经的,太伤感情了,但过了一天想了想,凉经的拿起来好好整理,就像象棋一样,你进步最快的时候不是你赢棋的时候,而是在输棋的时候。那废话不多说,就做个复盘吧。一面:1,经典自我介绍2,项目盘问,没啥好说的,感觉问的不是很多3,八股问的比较奇怪,他会深挖性地问一些,比如,我知道MMU,那你知不知道QMMU(记得是这个,总之就是MMU前面加一个字母)4,知不知道slab内存分配器-&gt;这个我清楚5,知不知道排序算法,排序算法一般怎么用6,写一道力扣的,最长回文子串反问:1,工作内容2,工作强度3,关于友商的问题-&gt;后面这个问题问HR去了,和中兴有关,数通这个行业和友商相关的不要提,这个行业和别的行业不同,别的行业干同一行的都是竞争关系,数通这个行业的不同企业的关系比较微妙。特别细节的问题我确实不知道,但一面没挂我。接下来是我被挂的二面,先说说我挂在哪里,技术性问题我应该没啥问题,主要是一些解决问题思路上的回答,一方面是这方面我准备的不多,另一方面是这个面试写的是“专业面试二面”,但是感觉问的问题都是一些主管面/综合面才会问的问题,就是不问技术问方法论。我以前形成的思维定式就是专业面会就是会,不会就直说不会,但事实上如果问到方法论性质的问题的话得扯一下皮,不能按照上面这个模式。刚到位置上就看到面试官叹了一口气,有一些不详的预感。我是下午1点45左右面的。1,经典自我介绍2,你是怎么完成这个项目的,分成几个步骤。我大致说了一下。你有没有觉得你的步骤里面缺了一些什么,(这里已经在引导我往他想的那个方向走了),比如你一个人的能力永远是不够的,,,我们平时会有一些组内的会议来沟通我们的所思所想。。。。3,你在项目中遇到的最困难的地方在什么方面4,说一下你知道的TCP/IP协议网络模型中的网络层有关的协议......5,接着4问,你觉得现在的socket有什么样的缺点,有什么样的优化方向?6,中间手撕了一道很简单的快慢指针的问题。大概是在链表的倒数第N个位置插入一个节点。————————————————————————————————————10.13晚更新补充一下一面说的一些奇怪的概念:1,提到了RPC2,提到了fu(第四声)拷贝,我当时说我只知道零拷贝,知道mmap,然后他说mmap是其中的一种方式,然后他问我知不知道DPDK,我说不知道,他说这个是一个高性能的拷贝方式3,MMU这个前面加了一个什么字母我这里没记,别问我了4,后面还提到了LTU,VFIO,孩子真的不会。
走呀走:华子二面可能会有场景题的,是有些开放性的问题了
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务