目录
严格的证明没有给出,只有解题思路,感兴趣可以去网上查证明,贪心问题证明还是很难的。
乘积最大
题目描述
输入描述
输出描述
输出一个整数,表示答案。
输入输出样例
输入
5 3
-100000
-10000
2
100000
10000
输出
999100009
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
实现代码:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N =100010;
const int mod = 1000000009;
typedef long long LL;
int n, k;
int a[N];
int main()
{
cin >> n >> k;
for (int i = 0 ; i < n; i++) cin >> a[i];
sort(a, a + n);
int i = 0, j = n - 1;//左右指针
LL res = 1;
int flag = 1;//看最后一个数是否为负数
//是奇数,就先把最后一个选了,然后就变为选偶数问题。
if (k % 2)
{
res = a[j];
if (res < 0) flag = -1;
k--;
j--;
}
//成对的选择,左右两对,看谁大
while(k)
{
LL l = (LL)a[i] * a[i + 1];
LL r = (LL)a[j] * a[j - 1];
//选左边两对
if (l * flag > r * flag)//若都是负数就乘-1,选小的,这样总值就负的少一点
{
i += 2;//指针移动
res = l % mod * res % mod;
}
else
{
j -= 2;//指针移动
res = r % mod * res % mod;
}
k -= 2;
}
printf("%lld", res);
}
原理思路:
主要分为两种情况,一种是k为奇数,一种是为偶数。
先排序。
在k为奇数时,我们先选择最后一个元素,这样就转化为了k为偶数问题。这里注意,判断一下最后一个元素是不是负数,若是负数,就记录一下sign = -1,因为如果最后一个是负数,其他全部数字也是负数,我们不可能找出最终结果为正数的答案,后面的选择就会发生变化。
然后我们分别定义两个指针,一个指向头,一个指向尾,求出头两对的乘积和尾两对的乘积,然后乘以sign,上面说了若都是负数的话,我们就要选择乘积最小的,这样负的越小,值反而越大。若sign是1,那么就正常的比较出两个中的最大值(一般情况),然后根据选择来移动指针,同时k也减小2。
当k为0时就代表选择完毕,记得定义res为long long类型。
付账问题
题目描述
输入描述
输出描述
输入输出样例
输入
5 2333
666 666 666 666 666
输出
0.0000
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
实现代码:
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N = 500010;
int n;
long double s;
int a[N];
int main()
{
cin >> n;
cin >> s;
for (int i = 0; i < n; i++) scanf("%d", &a[i]);
sort(a, a + n);//记得sort
long double res = 0;
long double avg = s * 1.0 / n;//总的平均值
for (int i = 0; i < n; i++)
{
long double cur = s / (n - i);//当前需要的平均值(当前需要交的钱), 除的是 n - i ,细节
//小于的话有多少给多少
if (a[i] < cur) cur = a[i];
//大于的话,就给当前的平均值就行
s -= cur;//总的需要交的钱减少了
res += (cur - avg) * (cur - avg);
}
printf("%.4llf", sqrt(res / n));//标准差
return 0 ;
}
原理思路:
先排序。
当一个人钱不够当前平均值时,就有多少拿多少。
当一个人钱够当前平均值时,就拿出当前平均值即可。
当前的平均值根据差的钱和人数,需要不断的更新。(可以根据注释看)