CF804 E- Three Days Grace
Problem Statement
TTT组询问, 每组询问给一个数组AiA_iAi和两个整数长度NNN及其值域[1,M][1,M][1,M].
你可以进行如下操作
- 选择一个数AiA_iAi若满足Ai=p⋅q(p,q≠1)A_i=p\cdot q(p,q\neq 1)Ai=p⋅q(p,q=1)则可以删去AiA_iAi把p,qp,qp,q加入数组.
- 你可以无数次地进行上述操作
问数组中的极差最小是多少, 即max(Ai)−min(Ai)\max(A_i)-\min(A_i)max(Ai)−min(Ai)在若干次操作后的最小值.
Solution
假设当前最大因子为KKK,我们考虑从小到大枚举最大的因子KKK.
则∀i,Ai≤K\forall i,A_i\leq K∀i,Ai≤K时, 我们需要让满足条件的AiA_iAi最大.
我们不妨设fif_ifi表示在最大因子不超过KKK的条件下, 数iii的可被分解为的最小因子的最大值为fif_ifi(即6=2×36=2\times 36=2×3则当K=3K=3K=3时f6=2f_6=2f6=2).
- 性质1: 显然有fi≤Kf_i\leq Kfi≤K.
- 性质2: 由于操作是将Ai=p⋅q(p,q≠1)A_i=p\cdot q(p,q\neq 1)Ai=p⋅q(p,q=1), 显然进行一次操作后AiA_iAi会被分解称为两个更小的数, 即满足p,q≤Aip,q\leq A_ip,q≤Ai.
由于我们从小到大枚举了最大因子KKK, 那么可能原先的数不能被小于等于KKK的数分解, 那么我们认为其最小因子的最大值为−INF-INF−INF.
我们设一开始f1=1,∀i>1,fi=−INFf_1=1,\forall i>1,f_i=-INFf1=1,∀i>1,fi=−INF.
我们从K=2K=2K=2开始, 从小到大枚举KKK.
当K=kK=kK=k时, 由于我们要让因子分解地尽量地大, 那就等价于尽可能地不被分解fk=kf_k=kfk=k(如性质2可得).
我们考虑更新fif_ifi由于Ai=p⋅qA_i=p\cdot qAi=p⋅q要求p,qp,qp,q均为AiA_iAi的因子, 我们直接从小到大枚举kkk的倍数.
假设, 当前需要更新的数为x=k⋅j(j>1)x=k\cdot j(j>1)x=k⋅j(j>1), 那么由于性质2, 可得fj≤K,fk=Kf_j\leq K,f_k=Kfj≤K,fk=K.
当xxx分解为jjj与kkk时, 其最小因子的最大值应当为fj(fj≤fk=K)f_j(f_j\leq f_k=K)fj(fj≤fk=K).
从小到大枚举KKK再进行上述更新即可, 当然由于我们让限制KKK逐步扩大, 那么fif_ifi的值也会随之变大, 因此我们可以用单调队列的方式进行更新.
时间复杂度为O(mlogm)O(m\log m)O(mlogm), 如果使用set维护时间复杂度为O(mlog2m)O(m\log^2m)O(mlog2m).
Code[O(mlog2m)][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;
}
这篇博客探讨了一个数组处理的问题,即如何通过操作减少数组中元素的最大值与最小值之差(极差)。文章介绍了动态规划的方法,从小到大枚举最大因子,利用单调队列优化更新过程,最终求出最小极差。同时,提供了C++代码实现,展示了解决这类问题的思路和技巧。

3925

被折叠的 条评论
为什么被折叠?



