本文用以分析一下标准答案, 如有错误,烦请予以指正。
题目:
给定 N 个整数 A1,A2,…AN。
请你从中选出 K 个数,使其乘积最大。
请你求出最大的乘积,由于乘积可能超出整型范围,你只需输出乘积除以 1000000009 的余数。
注意,如果 X<0, 我们定义 X 除以 1000000009 的余数是负(−X)除以 1000000009 的余数,即:0−((0−x)%1000000009)
输入格式
第一行包含两个整数 N 和 K。
以下 N 行每行一个整数 Ai。
输出格式
输出一个整数,表示答案。
数据范围
1≤K≤N≤105,
−105≤Ai≤105
输入样例1:
5 3
-100000
-10000
2
100000
10000
输出样例1:
999100009
输入样例2:
5 3
-100000
-100000
-2
-100000
-100000
输出样例2:
-999999829
A:正确
int main()
{
int n, k;
long long ans;
cin >> n >> k;
vector<long long> num;
for (int i = 0; i < n; i++)
{
int temp;
cin >> temp;
num.push_back(temp);
}
sort(num.begin(), num.end());//升序排列 1 2 3 4 5 ...
if (k % 2 != 0) //判断k是奇数还是偶数
{
ans = num.back(); //将最后一位给ans并出栈
k = k - 1;
num.pop_back();
}
else
ans = 1;
while (k > 0)//把最大的两个数的乘积给ans,然后再循环比较,相乘
{
if ((num[0] * num[1]) > num.at(num.size() - 1) * num.at(num.size() - 2))
{
ans = ans * num[0] * num[1] % 1000000009;
num.erase(num.begin(), num.begin() + 1);
}
else
{
ans = ans * num.at(num.size() - 1) * num.at(num.size() - 2) % 1000000009;
num.pop_back();
num.pop_back();
}
k -= 2;
}
cout << ans;
return 0;
}
B:错误,原因:元素下标不对应
#define ll long long
#define inf 0x7fffffff
const int N = 1e5 + 10; // 1*10^5 + 10
const int mod = 1e9 + 9;
int n, k;
int a[N];
ll ans = 1;
int main()
{
cin >> n >> k;
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
sort(a + 1, a + n + 1); //因为i是从1开始的,故为a+1, 第二项由函数定义可知,需为尾元素地址的下一个地址故为 a+n+1
int sign = 1;
if (k % 2) //判断k的奇偶
{
ans = a[n];
n--;
k--;
}
int i = 0, j = n; //错在这里,在输入的时候是从1开始的,而这里却是从0开始的
while (k)//和A一样
{
ll tmp1 = (ll)a[i] * a[i + 1], tmp2 = (ll)a[j] * a[j - 1];
if (tmp1 * sign > tmp2 * sign)
{
ans = (tmp1 % mod * ans) % mod;//他为什么要这么写呢?这也是我的第一个问题,感觉就和(tmp * ans)% mod 一样
i += 2;
}
else
{
ans = (tmp2 % mod * ans) % mod;
j -= 2;
}
k -= 2;
}
printf("%lld\n", ans);
return 0;
}
C:正确
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
#define mod 1000000009
const int N = 100010;
typedef long long LL;
int a[N];
int n, k;
int main()
{
cin >> n >> k;
for (int i = 0; i < n; i++)
{
scanf("%d", &a[i]);
}
sort(a, a + n);
LL res = 1;
//这里采用分布式的方法,分别判断k与n的关系,并各自做出反应
if (n == k)
{
for (int i = 0; i < n; i++)
{
res = (res * a[i]) % mod;
}
cout << res % mod;
return 0;
}
if (a[n - 1] < 0) //全负
{
if (k % 2 == 1)
{
for (int i = n - 1; i >= n-k; i--)
{
res = (res * a[i]) % mod;
}
}
else
{
for (int i = 0; i < k; i++)
{
res = (res * a[i]) % mod;
}
}
cout << res << endl;
return 0;
}
int l = 0, r = n - 1;
if (k % 2 == 1) //有正有负
{
res = a[r--];
k--;
}
while (k)
{
LL x = (LL)a[l] * a[l + 1], y = (LL)a[r] * a[r - 1];
if (x > y)
{
res = x % mod * res % mod;
l += 2;
}
else
{
res = y % mod * res % mod;
r -= 2;
}
k -= 2;
}
cout << res << endl;
return 0;
}
D:正确
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
#define mem(a, b) memset(a, b, sizeof(a))
#define mod 1000000009
typedef long long ll;
const int maxn = 1e6 + 5;
const double esp = 1e-7;
const int ff = 0x3f3f3f3f;
map<int, int>::iterator it;
struct node
{
ll x;
int f;
} a[maxn];
int n, k;
bool cmp(node x, node y)
{
return x.x > y.x;
}
ll solve(int o)
{
ll ans = 1;
int cnt = 0;
if (o == 0)
{
for (int i = 1; i <= k; i++)
{
ans = (ans * a[i].x) % mod;
if (a[i].f == 1)
cnt++;
}
}
else
{
for (int i = n; i > n - k; i--)
{
ans = (ans * a[i].x) % mod;
if (a[i].f == 1)
cnt++;
}
}
if (cnt & 1)
return ans * (-1);
return ans;
}
int main()
{
cin >> n >> k;
int flag = 0;
int cnt = 0;
for (int i = 1; i <= n; i++)
{
scanf("%lld", &a[i].x);
if (a[i].x < 0) //如果是负数,就给f赋值为1且将其转为正数
{
a[i].f = 1;
a[i].x = -a[i].x;
cnt++;
}
else if (a[i].x > 0)
a[i].f = 0;
else //等于0的话,就让下一个数将其覆盖
{
i--;
n--;
flag = 1;
}
}
sort(a + 1, a + n + 1, cmp); //倒序排列
ll ans = 0;
if (n < k)
ans = 0;
else if (cnt == n) //全是负数
{
if (k & 1)//判断k的奇偶
ans = solve(1);
else
ans = solve(0);
}
else if (cnt == 0) //全是正数
ans = solve(0);
else //有正有负
{
int tmp = 0;
for (int i = 1; i <= k; i++) //判断前面最大的几个数里面有几个负数用tmp记录
if (a[i].f == 1)
tmp++;
if (tmp % 2 == 0) //偶数个
ans = solve(0);
else //奇数个
{
ans = -1;
int p = -1, q = -1;
for (int i = k + 1; i <= n; i++) //在a[k+1]~a[n]之间找最大的正数
if (a[i].f == 0)
{
q = i;
break;
}
for (int i = k; i >= 1; i--) //在a[1]~a[k]之间找负数
if (a[i].f == 1)
{
p = i;
break;
}
if (p != -1 && q != -1) //找到了
{
swap(a[p], a[q]);
ans = solve(0);
swap(a[p], a[q]);
}
p = -1, q = -1;
for (int i = k + 1; i <= n; i++) //找这个范围里面的负数
if (a[i].f == 1)
{
q = i;
break;
}
for (int i = k; i >= 1; i--) //找正数
if (a[i].f == 0)
{
p = i;
break;
}
if (p != -1 && q != -1)
{
swap(a[p], a[q]);
ans = max(ans, solve(0));
swap(a[p], a[q]);
}
if (ans < 0)
ans = solve(1);
}
}
if (ans < 0)
if (flag)
{
cout << 0 << endl;
return 0;
}
cout << ans << endl;
return 0;
}