洛谷P1023 税收与补贴问题

题目背景

每样商品的价格越低,其销量就会相应增大。现已知某种商品的成本及其在若干价位上的销量(产品不会低于成本销售),并假设相邻价位间销量的变化是线性的且在价格高于给定的最高价位后,销量以某固定数值递减。(我们假设价格及销售量都是整数)

对于某些特殊商品,不可能完全由市场去调节其价格。这时候就需要政府以税收或补贴的方式来控制。(所谓税收或补贴就是对于每个产品收取或给予生产厂家固定金额的货币)

题目描述

你是某家咨询公司的项目经理,现在你已经知道政府对某种商品的预期价格,以及在各种价位上的销售情况。要求你确定政府对此商品是应收税还是补贴的最少金额(也为整数),才能使商家在这样一种政府预期的价格上,获取相对其他价位上的最大总利润。

总利润=单位商品利润*销量

单位商品利润=单位商品价格 - 单位商品成本 (- 税金 or + 补贴)

输入输出格式

输入格式:

输入的第一行为政府对某种商品的预期价,第二行有两个整数,第一个整数为商品成本,第二个整数为以成本价销售时的销售量,以下若干行每行都有两个整数,第一个为某价位时的单价,第二个为此时的销量,以一行-1,-1表示所有已知价位及对应的销量输入完毕,输入的最后一行为一个单独的整数表示在已知的最高单价外每升高一块钱将减少的销量。

输出格式:

输出有两种情况:若在政府预期价上能得到最大总利润,则输出一个单独的整数,数的正负表示是补贴还是收税,数的大小表示补贴或收税的金额最小值。若有多解,取绝对值最小的输出。

如在政府预期价上不能得到最大总利润,则输出“NO SOLUTION”。

输入输出样例

输入样例#1:  复制
31
28 130
30 120
31 110
-1  -1
15
输出样例#1:  复制
4

说明

所有数字均小于100000





参考链接:https://www.luogu.org/blog/user46408/solution-p1023

首先,这题的本质是一个数学题,其思想为设一个未知数x,然后列为无数个的不等式,所有不等式都要求使政府预算的那个价格的总利润大于其他价格的总利润,这样便可以解出x的范围,min<=x<=max,然后根据min和max的正负号来决定输出哪个。

以样例为例,我们要求

      (31-28+x)*110>=(28-28+x)*130
      (31-28+x)*110>=(29-28+x)*125
      (31-28+x)*110>=(30-28+x)*120
      (31-28+x)*110>=(32-28+x)*95

............. .............

这样一次类推,知道最后一个。

但是在编写程序时,这题有无数的问题。一、正如上例,由于题目中说的是线性排列,所以虽然题目中没有给出单价为29的情况,但是我们要自己推导出单价为29的情况;二、就是这题在判断最优时要用大于等于,由于我们不能保证他们一定能恰好除出来是一个整数,那么我们就要用一个float变量,但同时又存在一个恰好除出来是整数的情况,所以我们要对这两种情况进行判断,即看他们两个的差的绝对值是否比一个很小的数(1e-6)大,如果没有这个很小的数大,那么说明原来除出来是一个整数;三、这是C语言不同于Pascal的地方,对于实数取绝对值,不能用abs,而要用fabs,哎呦。


#include<stdio.h>
#include<iostream>
#include<math.h>
using namespace std;
#define N 10050
int main()
{
	//freopen("1.txt", "r", stdin);
	int pre, x, y, jian, m = 1, tmpp, tmpn, i, k = 0, kxy, min, max;
	float umin = -1e9, umax = 1e9;
	
	int price[N] = { 0 }, num[N] = { 0 };

	cin >> pre;
	cin >> x >> y;
	price[m] = x, num[m] = y;
	cin >> x >> y;
	while (x != -1 && y != -1)//循环读入数据并补充中间空缺的数据
	{
		if (x - price[m] == 1)
		{
			m++;
			price[m] = x;
			num[m] = y;
		}
		else
		{
			kxy = -(num[m] - y) / (x - price[m]);//kxy为中间每差1元减少的销量
			while (price[m] < x)
			{
				m++;
				price[m] = price[m - 1] + 1;
				num[m] = num[m - 1] + kxy;
			}
		}
		cin >> x >> y;
	}

	//不断增加售价直到销售量为0
	cin >> jian;
	tmpn = num[m]; tmpp = price[m];
	while (tmpn - jian > 0)    
	{
		m++;
		tmpp++; price[m] = tmpp;
		tmpn -= jian; num[m] = tmpn;
	}

	//如果已知价格中没有政府预估价则输出"NO SOLUTION"并退出程序
	for (i = 1; i <= m;i++)
	if (price[i] == pre)
	{
		k = i;
		break;
	}
	if (k == 0)
	{
		cout << "NO SOLUTION";
		return 0;
	}

	//(预估价的总利润-某价位上的总利润)/(某价位销量-预估价销量)=应该收的RMB
	for (i = 1; i < k;i++)
	if (((float)(num[k] * (price[k] - price[1]) - num[i] * (price[i] - price[1])) / (float)(num[i] - num[k])) <= umax)
		umax = (float)(num[k] * (price[k] - price[1]) - num[i] * (price[i] - price[1])) / (float)(num[i] - num[k]);

	//(某价位上的总利润 - 预估价的总利润) / (预估价销量 - 某价位销量) = 应该补贴的RMB
	//这个地方不理解的话建议解一下上文列出的不等式
	for (i = k + 1; i <= m;i++)
	if ((float)((num[i] * (price[i] - price[1]) - num[k] * (price[k] - price[1])) / (float)(num[k] - num[i])) >= umin)
		umin = (float)(num[i] * (price[i] - price[1]) - num[k] * (price[k] - price[1])) / (float)(num[k] - num[i]);

	if (umin>umax) cout << "NO SOLUTION";//解集为空
	else if (umin > 0)//需要补贴的情况
	{

		if (fabs(umin - (int)(umin)) > 1e-6) min = (int)(umin)+1;//float存在误差
		else
			min = (int)umin;
		cout << min;
	}
	else if (umax < 0)//需要收税的情况
	{
		if (fabs((int)(umax)-umax)>1e-6) max = (int)(umax)-1;//float存在误差
		else
			max = (int)(umax);
		cout << max;
	}
	else cout << 0;//若不需要补贴或收税
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

水之积也不厚,则其负大舟也无力

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值