1 solutions

  • 0
    @ 2025-6-17 14:35:30

    简单来说,这道题就是这样滴:
    在数组 a 中确定一个左端点 l 和一个右端点 r。
    记录 sumsumala_l​ 到 ara_r​ 的和。
    如果 sumsum 大于一个神奇的式子,那么就算出 rl+1r−l+1 的值,最后输出最大值就行了。
    ala_l​ 到 ara_r​ 的和可以使用前缀和解决,时间复杂度 O(n2)O(n^2 )
    然后我就写出了下面一份代码:

    #include <bits/stdc++.h>
    using namespace std;
    long long p[300005],sum[300005],a,b,c,n,maxx = -1;//开long long是好习惯,虽然我不知道不开行不行
    int main(){
    	cin >> n >> a >> b >> c;
    	for(long long i = 1;i <= n;i++){
    		cin >> p[i];
    		sum[i] = sum[i-1] + p[i];//前缀和,sum[i]存储的是p[1] ~ p[i]的和
    	}
    	for(long long l = 1;l <= n;l++){
    		for(long long r = l;r <= n;r++){
    			if(sum[r] - sum[l-1] > a * (b * r - c * l)){//sum[r] - sum[l-1]代表了p[l] ~ p[r]的和
    				maxx = max(maxx,r-l+1);//满足式子就求最大值呗
    			}
    		}
    	}
    	cout << maxx;
    	return 0;
    }
    
    

    然后成功的 TLE 了,只拿到了 60 分。
    为什么呢?题目中的 n 达到了 3×1053×10^5 ,所以说 O(n2)O(n^2 ) 是肯定 AC 不了滴!
    我们需要把时间复杂度压缩到近似于 O(nlogn)O(nlogn)。 让我们分析一下题目,已知我们求的是 rl+1r−l+1 的最大值,所以 r 和 l 的差值一定要尽量的大,而这个奇奇怪怪的式子又告诉我们,如果 r 和 l 的差值越大,条件就越难满足,如果不能满足,就是差值太大了。
    所以说,一个名叫二分的东东就很有用了。
    建立一个数组 f,TA 存储的是左端点耗费的权值。

    fi=min(fi1,sumi1a×c×i)f_i​ =min(f_{i−1}​ ,sum_{i−1}​ −a×c×i)
    其中 sum 是前缀和数组。
    为肾木呢?
    序列中的第 l 至 r 项之和大于 a×(b×rc×l)a×(b×r−c×l)。 也就是说序列中的第 1 至 r 项之和减去序列中的第 1 至 l−1 项之和大于 a×b×ra×c×la×b×r−a×c×l
    所以 sumrsuml1a×b×r+a×c×lsum_r​ −sum_{l−1}​ −a×b×r+a×c×l 大于 0。
    所以 sumra×b×rsum_r​ −a×b×r 大于 suml1a×c×lsum_{l−1}​ −a×c×l
    其中右端点的部分就是 sumra×b×rsum_r​ −a×b×r。 左端点的部分是 suml1a×c×lsum_{l−1}​ −a×c×l
    如果 fif_i​fi1f_{i−1} 还要大,那肯定取 fi1f_{i−1}​ 啊, rl+1r−l+1 足足能大 1 啊!
    接下来,用 i 枚举 1∼n,表示 1∼i 中的最大值就行了。

    • 1

    Information

    ID
    158
    Time
    1000ms
    Memory
    256MiB
    Difficulty
    5
    Tags
    # Submissions
    1
    Accepted
    1
    Uploaded By