[NWERC 2017]Factor-Free Tree

这是一篇关于算法的博客,主要讨论如何找到区间内的根节点,使得区间内的每个数与根节点互质。通过质因数分解预处理,可以有效地判断数之间的互质关系,并采用双指针方法确保线性时间复杂度。文章提供了详细的代码实现。
摘要由CSDN通过智能技术生成

Factor-Free Tree

题解

挺有趣的一道题。

我们首先应该很容易发现,对于一段区间,这段区间中任意一个与区间中其他数互质的数都可以作为这段区间的根。
因为如果这个数做根时会使其子区间无解,即使其他数做了根这个子区间无解的地方依旧会被传递下去,最后也一定会产生无解的状况。
所以,对于一段区间,我们如果找到了一个与该区间内其他数互质的数,我们可以直接将其提出来做根。

对于如何判断一个数是否与一段区间内其他数互质,我们可以先预处理出这个数所有的质因数,很明显,对于一个小于 1 0 7 10^7 107的数,不同的质因数不会超过10个。
然后我们往前往后找第一个与其有相同质因数,即第一个不与它互质的数。
很明显,如果当前区间在找出来的这个区间中,那就可以。
至于这个区间,我们可以将其预处理出来。

注意扫的时候我们不能从一边扫过去,要从两边扫向中间,这样才能保证时间复杂度严格 O ( n l o g   n ) O(nlog\, n) O(nlogn)
如果从一边扫的话是可以被卡到 O ( n 2 ) O\left(n^2\right) O(n2)的。

源码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define MAXN 1000005
#define reg register
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int,int> pii;
const int INF=0x7f7f7f7f;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
int n,prime[MAXN],cntp,pre[MAXN*10],fa[MAXN],idx,ls[MAXN],rs[MAXN],vis[MAXN];
bool oula[MAXN*10];
struct Number{
	int x,sta[10],stak;
	void work(){while(x>1){if(sta[stak]!=pre[x])sta[++stak]=pre[x];x/=prime[pre[x]];}}
}a[MAXN];
void init(){
	for(int i=2;i<=1e7;i++){
		if(!oula[i])prime[++cntp]=i,pre[i]=cntp;
		for(int j=1;j<=cntp&&1ll*i*prime[j]<=1e7;j++){
			oula[i*prime[j]]=1;pre[i*prime[j]]=j;
			if(i%prime[j]==0)continue;
		}
	}
}
void sakura(int l,int r,int father){
	int L=l,R=r;if(l==r){fa[l]=father;return ;}if(l>r)return ;
	while(L<=R){
		if(ls[L]<l&&rs[L]>r){sakura(l,L-1,L);sakura(L+1,r,L);fa[L]=father;return ;}L++;
		if(ls[R]<l&&rs[R]>r){sakura(R+1,r,R);sakura(l,R-1,R);fa[R]=father;return ;}R--;
	}
	puts("impossible");exit(0);
}
signed main(){
	read(n);init();for(int i=1;i<=n;i++)read(a[i].x),a[i].work(),rs[i]=n+1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=a[i].stak;j++)
			ls[i]=max(ls[i],vis[a[i].sta[j]]),vis[a[i].sta[j]]=i;
	for(int i=1;i<=cntp;i++)vis[i]=n+1;
	for(int i=n;i>0;i--)
		for(int j=1;j<=a[i].stak;j++)
			rs[i]=min(rs[i],vis[a[i].sta[j]]),vis[a[i].sta[j]]=i;
	sakura(1,n,0);for(int i=1;i<=n;i++)printf("%d ",fa[i]);
	return 0;
}

谢谢!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值