CodeForces - 1706D2 Chopping Carrots (Hard Version) (整除分块+dp+单调性优化)
题目链接
显然每个\(p_i\)的决策都是独立的,因此实际上要解决的是这样一个问题:给定数轴上的一些带颜色的点,找一个最短的区间,使其包含所有颜色的点
1.首先把所有点的颜色和坐标扒出来。整数n被整除得到的所有可能的数只有\(O(\sqrt{n})\)个,这些数可以通过整除分块算法得到
2.根据动态规划的思想,设\(dp[i][j]\)为考虑了前i种颜色且选择的区间左端点为j时,右端点至少到哪才能包含所有颜色的点(初始时\(dp[i]=i\))。每加入一种颜色的点,就将dp的值更新一遍。由于更新是线性的,因此第一维可以去掉,类似背包
3.由于dp的值只增不减,且右边的值必定比左边的大,具有单调性,因此更新的时候可以用lazy的做法,最后从头到尾扫一遍即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10,inf=0x3f3f3f3f;
int a[N],n,m,R[N];
int main() {
int T;
for(scanf("%d",&T); T--;) {
for(int i=1; i<N; ++i)R[i]=i;
scanf("%d%d",&n,&m);
for(int i=1; i<=n; ++i) {
scanf("%d",&a[i]);
int k=a[i];
vector<int> vec;
for(int l=1,r; l<=min(k,m); l=r+1) {
int t=k/l;
r=t&&k/t<k?k/t:k;
vec.push_back(t);
}
vec.push_back(0);
reverse(vec.begin(),vec.end());
vec.push_back(inf);
for(int i=0; i<(int)vec.size()-1; ++i) {
int l=vec[i],r=vec[i+1];
R[l+1]=max(R[l+1],r);
}
}
for(int i=1; i<N; ++i)R[i]=max(R[i],R[i-1]);
int ans=inf;
for(int i=1; i<N; ++i)ans=min(ans,R[i]-i);
printf("%d\n",ans);
}
return 0;
}