2 条题解

  • 1
    @ 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
      @ 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;
      }
      
      • 1

      信息

      ID
      496
      时间
      1000ms
      内存
      256MiB
      难度
      7
      标签
      递交数
      57
      已通过
      12
      上传者