CF804 E-Three Days Grace

CF804 E- Three Days Grace

Problem Statement

T T T组询问, 每组询问给一个数组 A i A_i Ai和两个整数长度 N N N及其值域 [ 1 , M ] [1,M] [1,M].

你可以进行如下操作

  • 选择一个数 A i A_i Ai若满足 A i = p ⋅ q ( p , q ≠ 1 ) A_i=p\cdot q(p,q\neq 1) Ai=pq(p,q=1)则可以删去 A i A_i Ai p , q p,q p,q加入数组.
  • 你可以无数次地进行上述操作

问数组中的极差最小是多少, 即 max ⁡ ( A i ) − min ⁡ ( A i ) \max(A_i)-\min(A_i) max(Ai)min(Ai)在若干次操作后的最小值.

Solution

假设当前最大因子为 K K K,我们考虑从小到大枚举最大的因子 K K K.

∀ i , A i ≤ K \forall i,A_i\leq K i,AiK时, 我们需要让满足条件的 A i A_i Ai最大.

我们不妨设 f i f_i fi表示在最大因子不超过 K K K的条件下, 数 i i i的可被分解为的最小因子的最大值为 f i f_i fi(即 6 = 2 × 3 6=2\times 3 6=2×3则当 K = 3 K=3 K=3 f 6 = 2 f_6=2 f6=2).

  • 性质1: 显然有 f i ≤ K f_i\leq K fiK.
  • 性质2: 由于操作是将 A i = p ⋅ q ( p , q ≠ 1 ) A_i=p\cdot q(p,q\neq 1) Ai=pq(p,q=1), 显然进行一次操作后 A i A_i Ai会被分解称为两个更小的数, 即满足 p , q ≤ A i p,q\leq A_i p,qAi.

由于我们从小到大枚举了最大因子 K K K, 那么可能原先的数不能被小于等于 K K K的数分解, 那么我们认为其最小因子的最大值为 − I N F -INF INF.


我们设一开始 f 1 = 1 , ∀ i > 1 , f i = − I N F f_1=1,\forall i>1,f_i=-INF f1=1,i>1,fi=INF.

我们从 K = 2 K=2 K=2开始, 从小到大枚举 K K K.

K = k K=k K=k时, 由于我们要让因子分解地尽量地大, 那就等价于尽可能地不被分解 f k = k f_k=k fk=k(如性质2可得).

我们考虑更新 f i f_i fi由于 A i = p ⋅ q A_i=p\cdot q Ai=pq要求 p , q p,q p,q均为 A i A_i Ai的因子, 我们直接从小到大枚举 k k k的倍数.

假设, 当前需要更新的数为 x = k ⋅ j ( j > 1 ) x=k\cdot j(j>1) x=kj(j>1), 那么由于性质2, 可得 f j ≤ K , f k = K f_j\leq K,f_k=K fjK,fk=K.

x x x分解为 j j j k k k时, 其最小因子的最大值应当为 f j ( f j ≤ f k = K ) f_j(f_j\leq f_k=K) fj(fjfk=K).

从小到大枚举 K K K再进行上述更新即可, 当然由于我们让限制 K K K逐步扩大, 那么 f i f_i fi的值也会随之变大, 因此我们可以用单调队列的方式进行更新.

时间复杂度为 O ( m log ⁡ m ) O(m\log m) O(mlogm), 如果使用set维护时间复杂度为 O ( m log ⁡ 2 m ) O(m\log^2m) O(mlog2m).


Code [ O ( m log ⁡ 2 m ) ] [O(m\log^2m)] [O(mlog2m)]

由于懒得写单调队列了, 直接用一个set进行维护
const int maxm=5e6+10;
const int INF=1<<30;

int A[maxm],Ans,DP[maxm];
bool Visit[maxm];

void Solve(){
	static int N,M,i,j,To;
	read(N),read(M);
	for(i=1;i<=M;++i) Visit[i]=false; 
	for(i=1;i<=N;++i) read(A[i]),Visit[A[i]]=true; 
	set<pii> Now;
	DP[1]=1;
	for(i=2;i<=M;++i) DP[i]=-INF;
	for(i=1;i<=M;++i) if(Visit[i]) Now.insert({DP[i],i});
	Ans=1-Now.begin()->first;
	for(i=2;i<=M;++i){
		if(Visit[i]) Now.erase({DP[i],i}),Now.insert({i,i});
		DP[i]=i;
		int Tem=M/i;
		for(j=2;j<=Tem;++j){
			To=i*j;
			if(DP[To]<DP[j]){
				if(Visit[To]){
					Now.erase({DP[To],To});
					Now.insert({DP[j],To});
				}DP[To]=DP[j];
			}
		}Ans=min(Ans,i-Now.begin()->first);
	}
	printf("%d\n",Ans);
	return;
}
Tips: 本题难点在枚举顺序上, 当我们从小到大枚举的时候, 能获得到单调性这一特殊性质
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值