【每日一题】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;
} 每日一题 文章被收录于专栏
每日一题
海康威视公司福利 1134人发布
