洛谷 P1023 税收与补贴问题

题目背景

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

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

题目描述

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

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

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

输入输出格式

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

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

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

输入输出样例

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

分析:
一下子没看懂题(看了10分钟)。
先说大意:
政府想让这个物品卖31元,商家一定要利润最大,也就是说说,政府想要税收(补贴)x元时,商家利润最大时卖31元,要求x的值最小。
28为成本价,这时候可以卖出130件。
30为成本价,这时候可以卖出120件。
…….
当在31元以上时,每加1元,少卖15件。

因为“相邻价位之间的销量变化是均匀的”,因此28元卖130个,30元卖120个就可以知道
29元卖125个(平均每元减少的销量是(130-120) div (30-28)=5)

4代表补贴是4元,所以:
在卖28元的时候,总利润是:(28-28+4)*130=520元,
在卖29元的时候,总利润是:(29-28+4)*125=625元,
在卖30元的时候,总利润是:(30-28+4)*120=720元,
在卖31元的时候,总利润是:(31-28+4)*110=770元,
在卖32元的时候,总利润是:(32-28+4)*95=760元
……
这是就可以看到,当补贴4元时,31元利润最大,这是商家能拿到最大利润,政府也成功把价格弄到31元。

当补贴是0,1,2,3时,商家最大利润价格不是31元,政府也就达不到目的了。

方法1:这时,方法也显而易见了,暴力x,直达达到政府的目的,也要保证商家的利润。

方法2:我们不枚举X,带入式子有
在卖28元的时候,总利润是:(28-28+x)*130,
在卖29元的时候,总利润是:(29-28+x)*125,
在卖30元的时候,总利润是:(30-28+x)*120,
在卖31元的时候,总利润是:(31-28+x)*110,
在卖32元的时候,总利润是:(32-28+x)*95。
这时,要想利润最大,有

(31-28+x) 110>=(28-28+x)*130
(31-28+x)110>=(30-28+x)*120
(31-28+x) <script type="math/tex" id="MathJax-Element-262">*</script>110>=(32-28+x)*95
(注意,可以等于)

可得:
1.x<=16.5
2.x<=9
3.x>=3.33
取交集可得3.33<=x<=9,绝对值最小且为整数,很明显是4了。
至于无解,就是交集无整数了。

代码:

const
  maxn=50;
  maxm=10000;
var
  d:array[1..maxm] of longint;
  price,sell:array[1..maxn] of longint;
  k1,k2:real;
c,r,t,x,y,n,each,i,j,p,most,m,u1,u2:longint;
begin
  readln(n);
  c:=0;
  repeat
    readln(x,y);
    if (x=-1) and (y=-1) then break;
    inc(c);
    price[c]:=x;
    sell[c]:=y;
  until false;
  readln(m);
  p:=price[1];
  most:=price[c]+sell[c] div m;
  if (n<p)or(n>most) then
  begin
    writeln('NO SOLUTION');
    halt;
  end;
  for i:=1 to c-1 do
  begin
    each:=(sell[i]-sell[i+1]) div (price[i+1]-price[i]);
    for j:=price[i] to price[i+1]-1 do
      d[j]:=sell[i]-each*(j-price[i]);
  end;
  for i:=price[c] to most do       d[i]:=sell[c]-m*(i-price[c]);
  k1:=-maxlongint; k2:=maxlongint;
  for i:=p to most do
  begin
    r:=d[n]-d[i];
    t:=i*d[i]-n*d[n]-p*(d[i]-d[n]);
    if (r>0) and (t/r>k1) then
      k1:=t/r;
    if (r<0) and (t/r<k2) then
      k2:=t/r;
  end;
  if k1<-1e19 then u1:=-maxlongint
  else if (k1>0)and(k1-int(k1)>0) then u1:=trunc(k1)+1 else u1:=trunc(k1);
  if k2>1e19 then u2:=maxlongint
  else if (k2<0)and(int(k2)-k2>0) then u2:=trunc(k2)-1 else u2:=trunc(k2);
 if (u1<0)and(u2>0) then
  begin
    u1:=0;
    u2:=0;
  end;
  if u1>u2 then writeln('NO SOLUTION')
  else if abs(u1)<abs(u2) then writeln(u1)
  else writeln(u2);
  readln;
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值