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;
}

posted @ 2022-07-20 11:12  jrltx  阅读(178)  评论(0编辑  收藏  举报