税收与补贴问题——数论
题目来源
题目描述
题目背景
每样商品的价格越低,其销量就会相应增大。现已知某种商品的成本及其在若干价位上的销量(产品不会低于成本销售),并假设相邻价位间销量的变化是线性的且在价格高于给定的最高价位后,销量以某固定数值递减。(我们假设价格及销售量都是整数)
对于某些特殊商品,不可能完全由市场去调节其价格。这时候就需要政府以税收或补贴的方式来控制。(所谓税收或补贴就是对于每个产品收取或给予生产厂家固定金额的货币)
描述
你是某家咨询公司的项目经理,现在你已经知道政府对某种商品的预期价格,以及在各种价位上的销售情况。要求你确定政府对此商品是应收税还是补贴的最少金额(也为整数),才能使商家在这样一种政府预期的价格上,获取相对其他价位上的最大总利润。
总利润=单位商品利润*销量
单位商品利润=单位商品价格 - 单位商品成本 (- 税金 or + 补贴)
输入输出格式
输入格式:
输入的第一行为政府对某种商品的预期价,第二行有两个整数,第一个整数为商品成本,第二个整数为以成本价销售时的销售量,以下若干行每行都有两个整数,第一个为某价位时的单价,第二个为此时的销量,以一行-1,-1表示所有已知价位及对应的销量输入完毕,输入的最后一行为一个单独的整数表示在已知的最高单价外每升高一块钱将减少的销量。
输出格式:
输出有两种情况:若在政府预期价上能得到最大总利润,则输出一个单独的整数,数的正负表示是补贴还是收税,数的大小表示补贴或收税的金额最小值。若有多解,取绝对值最小的输出。
如在政府预期价上不能得到最大总利润,则输出“NO SOLUTION”。
输入输出样例
输入样例#1:
31
28 130
30 120
31 110
-1 -1
15
输出样例#1:
4
解题思路
- 政府要求在预期价格上取得最大值,那么我们可以对每一项数据都列出一个不等式,通过解不等式来得到补贴或者税收的取值范围。
- 设预期价格为 c ,其对应的销售量为 j ,成本为 i ,那么对于每一对数据 a b,都可以列出如下的不等式:
(c−i+x)⋅j≥(a−i+x)⋅b
- 由于等式两侧同时除以负数需要改变符号,因此我们需要分两种情况来讨论:
- 当
j>b
时,通过移项我们可以得到:
x≥(a−i)⋅b−(c−i)⋅j(j−b)从而得出了 x 的最小值
- 当
j<b
时,通过移项我们可以得到:
x≤(c−i)⋅j−(a−i)⋅b(b−j)从而得出了 x 的最小值
- 当
j>b
时,通过移项我们可以得到:
- 当数据中出现间隔的时候不需要对间隔中的每一组数据都求值,因为这个区间中的数据是按照固定的值递减,易证区间中所有数据所计算出的最大最小值均相同,因此只需要计算区间的左右端点的值即可
- 由于对预期价格进行了特殊处理,所以以特殊价格为后端点的区间会将不存在数据,因此要为这个区间填补一个元素
- 当超过最大价格之后由于同样是按照一个固定的值递减,那么我们也只需要计算一个超过最大值的数据即可
- 注意:当出现小数情况时最大值需要向下取整,最小值需要向上取整(cmath头文件中 ceil 函数向上取整 , floor函数向下取整)
源代码
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
struct data {
int a;
int b;
} small[500], big[500];// small保存所有价格小于预期价格的数据,big保存所有价格大于预期价格的数据
int sl,bl;
double MAX = 999999999,MIN = -999999999;
int e;
int expect;
int beyond;
void getMAX(){ // 计算最大值
for (int i = 1; i <= sl; i++) {
double tMAX = (expect - small[1].a) * e - (small[i].a - small[1].a) * small[i].b;
tMAX = tMAX / (small[i].b - e); // 计算对于当前价位时税金或补贴的最大值
MAX = min(MAX, tMAX);
}
}
void getMIN(){ // 计算最小值
for (int i = 1;i <= bl;i++) {
double tMIN = (big[i].a - small[1].a) * big[i].b - (expect - small[1].a) * e;
tMIN = tMIN / (e - big[i].b);// 计算对于当前价位时税金或补贴的最小值
MIN = max(MIN, tMIN);
}
}
int main() {
freopen("in.txt", "r", stdin);
cin >> expect;
int a,b;
while (true) {
cin >> a >> b;
if (a == -1 && b == -1)
break;
if (a < expect) { // 当读入的数据小于预期价格时
sl++;
small[sl].a = a;
small[sl].b = b;
} else if (a > expect) { // 当读入的数据大于预期价格时
bl++;
big[bl].a = a;
big[bl].b = b;
} else {
e = b;
}
}
cin >> beyond;
if (e == 0) { // 如果读入数据中不存在预期价格的数据
if (bl == 0) // 当读入的数据存在大于预期数据的情况
e = small[sl].b - (expect - small[sl].a) * beyond;
else // 当预期数据已经超过了所给出的最大价格
e = small[sl].b - (small[sl].b - big[1].b) / (big[1].a - small[sl].a) * (expect - small[sl].a);
}
if (small[sl].a != expect - 1) { // 添加一组价格正好是预期价格 -1 的数据,以填补预期价格的空缺
sl++;
small[sl].a = expect - 1;
small[sl].b = e + beyond;
}
bl++;
if (bl == 1) { // 填补一组超过最大价格的数据
big[bl].a = expect + 1;
big[bl].b = e - beyond;
} else {
big[bl].a = big[bl - 1].a + 1;
big[bl].b = big[bl - 1].b - beyond;
}
getMAX();
getMIN();
//MIN++;
//MAX--;
//cout << MIN << " " << MAX << endl;
MIN = ceil(MIN); // 最小值向上取整
MAX = floor(MAX); // 最大值向下取整
if (MIN > MAX)
cout << "NO SOLUTION";
else {
if(MAX < 0)
cout << MAX;
else if(MIN >= 0)
cout << MIN;
else
cout << 0;
}
return 0;
}