T1 可以了
题目描述

科技
数学
分析
此题一眼顶针鉴定为和平均数的性质有关。
我们发现,对于这个array的一个区间,如果他的平均值大于整个数组的平均值,那么另一部分的平均值一定小于整个数组的平均值。
由此,不难想到:
我们将数组中每个数先减去平均数,然后维护一个前缀和。
那么任一区间的的平均值可表示为
s
u
m
j
−
s
u
m
i
−
1
j
−
i
+
1
+
a
r
v
\frac{sum_j - sum_{i - 1}}{j - i + 1} + arv
j−i+1sumj−sumi−1+arv
此时问题转化为:问怎么选
s
u
m
I
sum_I
sumI,使得任一的j均可使
s
u
m
j
−
s
u
m
i
−
1
j
−
i
+
1
>
=
0
\frac{sum_j - sum_{i - 1}}{j - i + 1} >= 0
j−i+1sumj−sumi−1>=0
答案显然:选择最小的
s
u
m
i
sum_i
sumi
这样,此题便愉快的做完了。
TIPS:为了让浮点不出精度问题,我们将所有数扩大n倍,避开double
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 500005;
/*
it is obveriously that if the the numbers which Alice choose is larger than the average of the whole array,she must be win.
so we use average number to minus every number in the array.
the question then turn into : find the smallest index whose all the field start from it is bigger than 0.
It can be solved by using prefix and.
we can just find the minual of tham as j - 1,if then field if[j,i].
*/
int n,ans;
long long sum[N],s,a[N];
int main()
{
scanf("%d",&n);
for(int i = 1;i <= n;i++) {
scanf("%lld",&a[i]);
s += a[i];
}
for(int i = 1;i <= n;i++)
a[i] = a[i] * n - s;
for(int i = 1;i < n;i++) {
sum[i] = sum[i-1] + a[i];
ans = (sum[i] < sum[ans] ? i : ans);
}
printf("%d\n",ans + 1);
return 0;
}
T2 淘汰
题目描述

科技
反悔贪心
分析
此题为最优规划类问题,考虑贪心/DP。
此题需要用到反悔贪心。
其实一个显然的思路是:有券先用券,没有券考虑两种情况:
- a较小,直接加。
- a较大,把一个用券的变成不用的,然后用券。
所以,此题我们用3个堆,分别维护最小的未加入的a,最小的未加入的b,最小的已加入的b转a所需的代价。
直接转移即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 500005;
long long n,k,t,ans;
struct programdata{
long long a,b;
bool operator < (const programdata tmp) const {
return b < tmp.b;
}
}p[N];
//反悔贪心的反悔堆
priority_queue<pair<long long,long long>,vector<pair<long long,long long> >,greater<pair<long long,long long> > >q1,q2,q3;
bool vis[N];
int main()
{
scanf("%lld%lld%lld",&n,&k,&t);
for(int i = 1;i <= n;i++)
scanf("%lld%lld",&p[i].a,&p[i].b);
sort(p + 1,p + 1 + n);
for(int i = 1;i <= k && t >= 0;i++) {
t -= p[i].b;
vis[i] = 1;
ans++;
}
if(t < 0) {
printf("%lld\n",ans - 1);
return 0;
}
for(int i = 1;i <= n;i++) {
if(vis[i]) {
q3.push(make_pair(p[i].a - p[i].b,i));
} else {
q1.push(make_pair(p[i].a,i));
q2.push(make_pair(p[i].b,i));
}
}
while(t > 0) {//现在试图加入其他的点
while(vis[q1.top().second])
q1.pop();
while(vis[q2.top().second])
q2.pop();
long long o1 = q1.top().second,o2 = q2.top().second;
long long x = q1.top().first,y = q2.top().first,z = q3.top().first;
ans++;
if(x < y + z) {//情况1:直接用a更优
q1.pop();
t -= x;
vis[o1] = 1;
} else {//情况二:用b再调整出一个b用a更优
q2.pop();
q3.pop();
q3.push(make_pair(p[o2].a - p[o2].b,o2));
t -= y + z;
vis[o2] = 1;
}
}
if(t < 0)
ans--;
printf("%lld\n",ans);
return 0;
}

1238

被折叠的 条评论
为什么被折叠?



