2 条题解

  • 0
    @ 2024-7-17 10:29:11

    这题是洛谷P2717的弱化版,也是前缀和优化题

    假设有一个满足条件的子序列在 [al,ar][a_l,a_r] 间,显然,一共有 rl+1r-l+1 个数字,由于这些数的平均数大于等于 kk 即:

    al+al+1+.......+ar1+ar(rl+1)×ka_l+a_{l+1}+.......+a_{r-1}+a_r≥(r-l+1) \times k

    稍稍亿一变形可得

    al+al+1+.......+ar1+ar(rl+1)×k0a_l+a_{l+1}+.......+a_{r-1}+a_r-(r-l+1) \times k≥0

    (alk)+(al+1k)+.......+(ar1k)+(ark)0(a_l-k)+(a_{l+1}-k)+.......+(a_{r-1}-k)+(a_r-k)≥0

    所以我们可以在输入时对每个 aia_ikk,在查找时直接判断是否大于0即可

    再看前缀和优化部分,假设我们挑选了这样一个子序列:

    a1,a2,...,al,al+1,...,amid,...,ar1,ar,...a_1, a_2, ... , a_l, a_{l+1}, ... , a_{mid} , ... , a_{r-1}, a_r, ...

    显然 [al,amid][a_l,a_{mid}] 部分的和相当于 ala_l 的后缀和,而 [amid+1,ar][a_{mid+1},a_r] 部分的和相当于从 amid+1a_{mid+1} 开始,到 ara_r 的前缀和

    注意:从 amid+1a_ {mid+1} ​开始!!!!!

    因为序列是分为两部分的,如果从 a1a_1 开始,必然会把 [a1,amid][a_1, a_{mid}] 的部分多余算

    但你以为这就完了么?

    实际上手还会超时的!!!

    这就意味着我们得继续减复杂度

    毕竟是前缀和,我们只需要看区间和满足不满足要求,调换顺序不影响。所以可以通过排序来减少多余的区间计算

    我们可以将 [a1,amid][a_1, a_{mid}] 的部分从大到小排,剩下的部分从小到大排,再用双指针扫一遍,结束!

    上代码:

    #include<bits/stdc++.h>
    using namespace std;
    long long a[100001],s[100001];
    bool cmp(long long x,long long y){
    	return x>y;
    }
    int main(){
    	long long n,k,ans=0,j;
    	cin>>n>>k;
    	j=n;
    	for(int i=1;i<=n;i++){
    		cin>>a[i];
    		a[i]-=k;
    	}
    	int mid=(n+1)/2;
    	for(int i=1;i<=mid;i++) s[i]=s[i+1]+a[i];
    	for(int i=mid+1;i<=n;i++) s[i]=s[i-1]+a[i];
    	sort(s+1,s+mid+1,cmp);
    	sort(s+mid+1,s+n+1);
    	for(int i=1;i<=mid;i++){
    		while(j>mid&&s[i]+s[j]>=0) j--;
    		ans+=(n-j);
    	}
    	cout<<ans;
    }
    
    • -2
      @ 2024-8-1 16:35:48

      #include<bits/stdc++.h> using namespace std; long long a[100001],s[100001]; bool cmp(long long x,long long y){ return x>y; } int main(){ long long n,k,ans=0,j; cin>>n>>k; j=n; for(int i=1;i<=n;i++){ cin>>a[i]; a[i]-=k; } int mid=(n+1)/2; for(int i=1;i<=mid;i++) s[i]=s[i+1]+a[i]; for(int i=mid+1;i<=n;i++) s[i]=s[i-1]+a[i]; sort(s+1,s+mid+1,cmp); sort(s+mid+1,s+n+1); for(int i=1;i<=mid;i++){ while(j>mid&&s[i]+s[j]>=0) j--; ans+=(n-j); } cout<<ans; }

      • 1

      信息

      ID
      496
      时间
      1000ms
      内存
      256MiB
      难度
      8
      标签
      递交数
      54
      已通过
      10
      上传者