U329011 trie pi 题解

花了2d打磨出来的题目,觉得很有意思。

先讲点无关的,这道题有两版,但都是对要求的量进行改动。

1.第一次要求的是y属性为a与y属性为b的两个节点的路径权值之和,对于要求的这个量,我们设v[i]为i到根节点的权值之和。那么我们先对a,b进行质因数分解,设dcg为a,b分解质因数后最长公共前缀的乘积,那么答案就是v[a]+v[b]-2*v[dcg]。

但可能会有人问wuhupai为什么不用这版,那是因为我发现了一个很有意思的性质:
y属性为a的这个点到根节点的路径权值和是a的最大质因子-1。解释起来也很简单:路上的权值全部都消掉了(觉得不理解可以手模一下),于是我想用这个性质搞点事情。于是与空气斗智斗勇3h,连续想出了5个时间复杂度能过的暴力,然后我发现要卡掉log n 的暴力要达到2^1e9也就是约3e8位的数,这肯定是不行的,于是今天早上灵光一闪,想出了这个题。

这道题的突破口就是y属性为a的这个点到根节点的路径权值和是a的最大质因子-1这个性质。我们只要能知道a的最大质因子就可以了,但是分解质因数的复杂度是O(n)的,1e7*1e7显然不能让我们通过此题,于是我们可以通过构造trie pi树的方式来用le7的时间预处理出1-1e7内所有数的最大质因子,然后边读入边取max就行了

#include<bits/stdc++.h>
using namespace std;
bool vis[10000005];
long long n,x,maxx=-1,len=0,num[5000000],v[10000005];
inline long long read(){
    char c=getchar();
    long long x=0,f=1;
    while(c<48){if(c=='-')f=-1;c=getchar();}
    while(c>47)x=(x*10)+(c^48),c=getchar();
    return x*f;
}
void solve(){
	for(long long i=2;i<=10000000;i++){
		if(vis[i]==false){
			len++;
			num[len]=i;
		}
		for(long long j=1;j<=len&&i*num[j]<=10000000;j++){
			vis[i*num[j]]=true;
			if(i%num[j]==0) break;
		}
	}
}
void dfs(long long from,long long sum){
	v[sum]=num[from];
	for(long long i=from;i<=len&&sum*num[i]<=10000000;i++){
		dfs(i,sum*num[i]);
	}
}
int main(){
	solve();
	dfs(1,1);
	v[1]=1;
	n=read();
	for(long long i=1;i<=n;i++){
		x=read();
		maxx=max(maxx,v[x]);
	}
	cout<<maxx-1;
	
	return 0;
}
posted @ 2024-02-27 10:11  wuhupai  阅读(4)  评论(0编辑  收藏  举报