2 条题解
-
0
#include<bits/stdc++.h> using namespace std; #define int long long const int N = 1e6+5; int a[200100], l[200100], r[200100], he[200100]; void solve() { int n, m, v; cin >> n >> m >> v; for(int i = 1; i <= n; i++){ cin >> a[i]; } l[0] = 0; int sum = 0; // 该代码是求从1到n,满足美味值大于v的人数 // 例如,此时l[i]的值为3,那就代表从1到i有3个人满足分到蛋糕的美味值大于v for(int i = 1; i <= n; i++) { l[i] = l[i - 1]; sum += a[i]; if (sum >= v){ l[i]++; sum = 0; } } sum = 0; r[n + 1] = 0; // 与l代表的意义一样,之所以从n到1,是因为最终的答案肯定是一个区间和 // 假如是[L,R],那整个n就被分为三部分[1,L-1],[L,R],[R+1,n],由于不清楚R+1,所以我们没法从R+1到n // 但是我们可以从n到R+1,那为什么不直接用之前的l数组呢? // 那是因为他们两个中间隔着[L,R],而l数组记录了[L,R],会对之后的数据产生影响 for(int i = n; i >= 1; i--) { r[i] = r[i + 1]; sum += a[i]; if (sum >= v) { r[i]++; sum = 0; } } he[0] = 0;//前缀和,用于计算最终答案。 for (int i = 1; i <= n; i++) { he[i] = he[i - 1] + a[i]; } int ans = -1; //因为从1到n,美味值至少为v的人数达到m,所以最终答案的值不为-1。 if (l[n] >= m) { ans = 0; } // 开始遍历区间[L,R],这种方法叫双指针,可以去学一学 // 先固定右端点r1,移动左端点l1,当左端点大于右端点时,我们把此时的右端点移到左端点。 int r1 = 1, l1 = 1; for (l1 = 1; l1 <= n; l1++) { if (l1 > r1){ r1 = l1; } //前提条件成立,开始求最大值(通过移动右端点),直到前提条件不符合。 while (l[l1 - 1] + r[r1 + 1] >= m && r1 <= n) { ans = max(ans, he[r1] - he[l1 - 1]); r1++; } } cout << ans << '\n'; } signed main() { ios::sync_with_stdio(0); cin.tie(0), cout.tie(0); int T = 1; cin >> T; while (T--) solve(); return 0; } -
0
这道题不难想到,最终的答案肯定是一个区间和,由于我们要在保证软件ACM成员都开心的情况的条件下,保证自己的最多,那既然最多,其他成员的美味值就恰好为v,或者第一次大于v的时候就停止分,这样确保lfq分到的是最多的,我们可以分为三个区间,lfq分在[L,R]中的蛋糕,那剩余的[1,L-1],[R+1,n]的值的和要>=m,于是就有下面的代码
#include <bits/stdc++.h>
using namespace std;
long long a[200100], l[200100], r[200100], he[200100];
int main()
{
int t;
scanf("%d", &t);
for (int i = 1; i <= t; i++)
{
int n, m, v;
scanf("%d%d%d", &n, &m, &v);
for (int i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);
}
l[0] = 0;
long long sum = 0;
for (int i = 1; i <= n; i++)//该代码是求从1到n,满足美味值大于v的人数,例如,此时l[i]的值为3,那就代表从1到i有3个人满足分到蛋糕的美味值大于v
{
l[i] = l[i - 1];
sum += a[i];
if (sum >= v)
{
l[i]++;
sum = 0;
}
}
sum = 0;
r[n + 1] = 0;
for (int i = n; i >= 1; i--)//与l代表的意义一样,之所以从n到1,是因为最终的答案肯定是一个区间和,假如是[L,R],那整个n就被分为三部分[1,L-1],[L,R],[R+1,n],由于不清楚R+1,所以我们没法从R+1到n,但是我们可以从n到R+1,那为什么不直接用之前的l数组呢?那是因为他们两个中间隔着[L,R],而l数组记录了[L,R],会对之后的数据产生影响
{
r[i] = r[i + 1];
sum += a[i];
if (sum >= v)
{
r[i]++;
sum = 0;
}
}
he[0] = 0;//前缀和,用于计算最终答案。
for (int i = 1; i <= n; i++)
{
he[i] = he[i - 1] + a[i];
}
long long ans = -1;
if (l[n] >= m)//因为从1到n,美味值至少为v的人数达到m,所以最终答案的值不为-1。
{
ans = 0;
}
int r1 = 1;//开始遍历区间[L,R],这种方法叫双指针,可以去学一学,先固定右端点r1,移动左端点l1,当左端点大于右端点时,我们把此时的右端点移到左端点。
int l1 = 1;
for (l1 = 1; l1 <= n; l1++)
{
if (l1 > r1)
{
r1 = l1;
}
while (l[l1 - 1] + r[r1 + 1] >= m && r1 <= n)//前提条件成立,开始求最大值(通过移动右端点),直到前提条件不符合。
{
ans = max(ans, he[r1] - he[l1 - 1]);
r1++;
}
}
printf("%lld\n", ans);
}
return 0;
}
- 1
信息
- ID
- 1188
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 12
- 已通过
- 2
- 上传者