CF2086B题解
由于是晚上精力不太好,所以昨天第一次打 CFdiv.2 只切了两道题……
首先我们发现这个循环虽然看似 \(n \times k\) 个数都要统计是否有和 \(\ge x\) 的区间,但是实际上你会发现只需要遍历 \(n\) 个元素,二分看一下对于这个数在第 \(i(i \le k)\) 个循环是否有和 \(\ge x\) 的区间,判断是否有和 \(\ge x\) 的区间可以用后缀和的方法,因为你最优的 \(r\) 的取值一定是第 \(n \times k\) 个数,因为 \(a_i\) 均非负,然后 \(r\) 既然确定了,那对于任意一个 \(j(j \le n)\) 下标,它的第 \(i(i \le k)\) 次循环到 \(r\) 的和就是 \(pre_{j}+(k-i) \times sum\)(\(pre\) 虽然是前缀的英文,但是作者不知道后缀的英文,所以拿前缀的英文代替后缀的英文,\(sum\) 就是 \(\sum_{i = 1}^n a_i\)),你会发现它有单调性,所以可以二分算出以 \(j\) 为循环下标,最多能在第几次循环还能满足和 \(\ge x\),然后对于所有的 \(j\),统计答案即可。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
long long pre[N];
int a[N];
signed main()
{
int _;
scanf("%d",&_);
while(_--)
{
int n,k;
long long x,sum = 0;
scanf("%d %d %lld",&n,&k,&x);
for(int i = 1;i<=n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
pre[n+1] = 0;
for(int i = n;i>=1;i--)
{
pre[i] = a[i]+pre[i+1];
}
long long cnt = 0;
for(int i = 1;i<=n;i++)
{
int l = 1,r = k,ans = 0;
while(l<=r)
{
int mid = l+r>>1;
if(pre[i]+(k-mid)*sum>=x)
{
ans = mid;
l = mid+1;
}
else
{
r = mid-1;
}
}
cnt+=ans;
}
printf("%lld\n",cnt);
}
return 0;
}

浙公网安备 33010602011771号