Luogu 1023 - 税收与补贴问题 - [数学题]
题目链接:https://www.luogu.org/problemnew/show/P1023
题目背景
每样商品的价格越低,其销量就会相应增大。现已知某种商品的成本及其在若干价位上的销量(产品不会低于成本销售),并假设相邻价位间销量的变化是线性的且在价格高于给定的最高价位后,销量以某固定数值递减。(我们假设价格及销售量都是整数)
对于某些特殊商品,不可能完全由市场去调节其价格。这时候就需要政府以税收或补贴的方式来控制。(所谓税收或补贴就是对于每个产品收取或给予生产厂家固定金额的货币)
题目描述
你是某家咨询公司的项目经理,现在你已经知道政府对某种商品的预期价格,以及在各种价位上的销售情况。要求你确定政府对此商品是应收税还是补贴的最少金额(也为整数),才能使商家在这样一种政府预期的价格上,获取相对其他价位上的最大总利润。
总利润 = 单位商品利润 $\times$ 销量
单位商品利润 = 单位商品价格 - 单位商品成本 (- 税金 or + 补贴)
输入输出格式
输入格式:
输入的第一行为政府对某种商品的预期价,第二行有两个整数,第一个整数为商品成本,第二个整数为以成本价销售时的销售量,以下若干行每行都有两个整数,第一个为某价位时的单价,第二个为此时的销量,以一行 $-1,-1$ 表示所有已知价位及对应的销量输入完毕,输入的最后一行为一个单独的整数表示在已知的最高单价外每升高一块钱将减少的销量。
输出格式:
输出有两种情况:若在政府预期价上能得到最大总利润,则输出一个单独的整数,数的正负表示是补贴还是收税,数的大小表示补贴或收税的金额最小值。若有多解,取绝对值最小的输出。
如在政府预期价上不能得到最大总利润,则输出“NO SOLUTION”。
输入输出样例
输入样例#1:
31
28 130
30 120
31 110
-1 -1
15
输出样例#1:
4
说明
所有数字均小于100000
题解:
首先,不妨计算出从“成本价”到“销量为零的价格”,所有整数单价以及其对应的销量。
设成本价为 $p$,目标售价为 $T_{价格}$ 及其对应销量为 $T_{销量}$,所有可能的售价为 $P_{价格}$ 及其对应销量为 $P_{销量}$,假设补贴(税收)为 $x$,则有:
$(T_{价格}-p+x)T_{销量} \ge (P_{价格}-p+x)P_{销量}$
化为:
$x(T_{销量} - P_{销量}) \ge (P_{价格}-p)P_{销量} - (T_{价格}-p)T_{销量}$
因此,当 $T_{销量} - P_{销量} > 0 $ 时,为 $x \ge [(P_{价格}-p)P_{销量} - (T_{价格}-p)T_{销量}] / (T_{销量} - P_{销量})$;
当 $T_{销量} - P_{销量} < 0 $ 时,为 $x \le [(P_{价格}-p)P_{销量} - (T_{价格}-p)T_{销量}] / (T_{销量} - P_{销量})$;
这样一来,所有的不等式联立起来,就对 $x$ 有一个区间限定 $[L,R]$,根据这个区间限定选择输出答案即可。
AC代码:
#include<bits/stdc++.h> using namespace std; typedef pair<int,double> P; const double eps=1e-8; vector<P> v; P t; int lst,d; inline bool equ(double a,double b) { return fabs(a-b)<eps; } int main() { cin>>t.first; t.second=0; P tmp; while(cin>>tmp.first>>tmp.second) { if(tmp.first==-1 && tmp.second==-1) break; v.push_back(tmp); } sort(v.begin(),v.end()); lst=v[0].first; for(int i=0,j=1,sz=v.size(); j<sz; i++,j++) { double a=(v[i].second-v[j].second)/(v[i].first-v[j].first); double b=v[i].second-v[i].first*a; for(int x=v[i].first+1;x<v[j].first;x++) v.push_back(make_pair(x,a*x+b)); } sort(v.begin(),v.end()); cin>>d; while(1) { P last=v.back(); if(last.second-d>0) v.push_back(make_pair(last.first+1,last.second-d)); else break; } //for(auto x:v) printf("%d %f\n",x.first,x.second); int pos=lower_bound(v.begin(),v.end(),t)-v.begin(); t=v[pos]; //printf("%d %f\n",t.first,t.second); double L=-1e11,R=1e11; for(auto p:v) { if(p==t) continue; if(t.second>p.second) { L=max(L,((p.first-lst)*p.second-(t.first-lst)*t.second)/(t.second-p.second)); } if(t.second<p.second) { R=min(R,((p.first-lst)*p.second-(t.first-lst)*t.second)/(t.second-p.second)); } } //printf("%f %f\n",L,R); if(L>R) printf("NO SOLUTION\n"); else if(L>0) printf("%.0f\n",ceil(L)); else if(R<0) printf("%.0f\n",floor(R)); else printf("0\n"); }