时隔不知道多久我又来更新题解了(拖更qwq)

本题为什么是一个双指针的题目呢?首先看题目里说的,要维护的是连续区间的最短长度并且该区间内还需要保证权值之和大于x,所以我们就需要维护两个指针(变量)来实现查找一段连续的区间;

我们来看看右移右指针和右移左指针会有什么变化:

当右移右指针时,区间长度变大,这显然背离了我们想要找的“最短长度”,但是他又会使总和变大

当右移左指针时,区间长度变小,的确满足了我们需要的“最短长度”,但是他又会使区间的总和减小

那该怎么办呢?所以此时我们要用的思维就是双指针了,同时维护两个指针(变量),从而实现查找出既满足区间长度最短又满足权值之和大于x的

注意到我前面标红的字体,如果我们能让右移右指针的时候满足了总和最大的基础上,尽可能的去右移左指针从而缩短区间长度,这不就满足了我们的需求吗awa

所以整体思路:

1.右移右指针

2.在右移的同时检查当前的总和(cursum)是否已经大于x

2.1如果大于了x,那么就将左指针向右移动直到当前总和刚好不再大于x

2.2如果仍然小于x,那么更没有右移左指针的必要了(这样会使当前的总和更小而不是更大),所以依旧右移右指针

代码如下(结合注释看,很明显的)

void _()
{
    cin >> n >> x;
    vi a(n + 2);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    int l = 1, cursum = 0;
    int minlen = n + 1; // 大小为n+1可保证一定比答案大
    int ansl = -1, ansr = -1;
    // 前面全是初始化和输入,不必多说了
    for (int r = 1; r <= n; r++)
    {
        // 在不断右移右指针的同时对当前的cursum更新
        cursum += a[r];
        while (cursum >= x)
        {
            // 但是如果cursum比x大了,这就说明有可能让左指针右移从而收缩边界,使区间长度更短
            int curlen = r - l + 1; // 当前的区间长度
            if (curlen < minlen)    // 如果当前的区间长度比最小的还要小,那么就可以更新答案了
            {
                // 更新不仅要更新长度,还需要更新答案,并且答案只能在这种情况下更新因为如果curlen还不比minlen小的时候更新是会使答案偏大的
                minlen = curlen;
                ansl = l;
                ansr = r;
            }
            // 注意此时还在while循环里,每当左指针右移一位,cursum就要减去a[l]因为他已经不在区间内了
            cursum -= a[l];
            l++; // 右移左指针
        }
    }
    cout << ansl << " " << ansr << endl;
}

觉得我讲的不错,喜欢的话请为我点个赞吧awa