题目
在火星上有个魔法商店,提供魔法优惠券。每个优惠劵上印有一个整数面值K,表示若你在购买某商品时使用这张优惠劵,可以得到K倍该商品价值的回报!该商店还免费赠送一些有价值的商品,但是如果你在领取免费赠品的时候使用面值为正的优惠劵,则必须倒贴给商店K倍该商品价值的金额…… 但是不要紧,还有面值为负的优惠劵可以用!(真是神奇的火星)
例如,给定一组优惠劵,面值分别为1、2、4、-1;对应一组商品,价值为火星币M$7、6、-2、-3,其中负的价值表示该商品是免费赠品。我们可以将优惠劵3用在商品1上,得到M$28的回报;优惠劵2用在商品2上,得到M$12的回报;优惠劵4用在商品4上,得到M$3的回报。但是如果一不小心把优惠劵3用在商品4上,你必须倒贴给商店M$12。同样,当你一不小心把优惠劵4用在商品1上,你必须倒贴给商店M$7。
规定每张优惠券和每件商品都只能最多被使用一次,求你可以得到的最大回报。
输入格式:
输入有两行。第一行首先给出优惠劵的个数N,随后给出N个优惠劵的整数面值。第二行首先给出商品的个数M,随后给出M个商品的整数价值。N和M在[1, 106]之间,所有的数据大小不超过230,数字间以空格分隔。
输出格式:
输出可以得到的最大回报。
输入样例:
4 1 2 4 -1
4 7 6 -2 -3
输出样例:
43
解法
思路
- 首先将优惠券和商品进行升序排列或者降序排列(如果两个数组的元素全为正,那么这两个数组一定要降序排列,如果两个数组元素全为负,那么一定要升序排列,其余情况升序降序都可以),然后依次地将优惠券和商品的对应值相乘(就是两个数组下标相同的值),然后累加,一旦发现乘积为负,就停止累加。
- 从两个数组都从数组的最后一个元素开始相乘,然后累加,一旦发现乘积为负,就停止累加。
- 输出最后的累加结果。
实现
#include<stdio.h>
#include<stdlib.h>
void InputNumber(int *P, int N)
{
int i;
for(i=0; i<N; i++)
{
scanf("%d", &P[i]);
}
}
int compareID(const void *a, const void *b)
{
int k = *((const int *)a) - *((const int *)b);
return -k;
}
int main()
{
int N,M;
scanf("%d", &N);
int *PN = (int *)malloc(N*sizeof(int));
InputNumber(PN, N);
scanf("%d", &M);
int *PM = (int *)malloc(M*sizeof(int));
InputNumber(PM, M);
qsort(PN, N, sizeof(int), compareID);
qsort(PM, M, sizeof(int), compareID);
int i;
int sum = 0;
int tmp;
int tag = N>M?M:N; //get the min
for(i=0; i<tag; i++)
{
tmp = PN[i]*PM[i];
if(tmp>0)
sum = sum + tmp;
else
break;
}
if(i!=tag)
{
int countN = N-1;
int countM = M-1;
tmp = PN[countN]*PM[countM];
while(tmp>0)
{
sum = sum + tmp;
countM--;
countN--;
tmp = PN[countN]*PM[countM];
}
}
printf("%d", sum);
}
注意:上述代码的tag是为了检测for循环退出是因为遇到了乘积为负,还是两个数组中某一个数组遍历完成,如果一旦遍历完成,就不需要再进行后续的反向计算了。