NOIP2000 税收与补贴问题

NOIP2000 税收与补贴问题


写在前面

刚开始做题的时候一直没明白这题什么意思…卡了好久
然后直接忽略了"相邻价位间销量的变化是线性"这个重要条件,开始做题
解题思路是对了,就是做不出来,弄了我一个晚上


题目标签

  • 数论-数学
  • 枚举暴力-其他

题目介绍

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

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

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

总利润=单位商品利润 \times × 销量

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

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

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

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

输入输出样例
输入 #1 复制
31
28 130
30 120
31 110
-1 -1
15
输出 #1 复制
4
说明/提示
所有数字均小于100000


解题思路

难点解析

“相邻价位间销量的变化是线性”表示两个输入数据满足y=kx+b的关系。
设两数分别为较低价格,较高价格,价格∈(较低价格,较高价格),则价格可由y=kx+b求得。

完整思路

1:把用户输入的价格和销量通通存进数组里。
2:如果发现有的价格和销量用户没输入则按线性的规则自己写入。
3:在用户输入的最大价格后面按用户输入的递减数量把最后所有销量不为零的价格补充完整。
4:现在,你已经有了一个存有所有销量大于等于零的价格-销量表。
5:从1/-1开始枚举所有可能的补贴或税收,对应的,如果此时预期价的总利润达到最大,则输出答案。


代码展示

#include 
#include 
#include 
using namespace std;
#define MAX_SIGH 100000 //题目:所有数字均小于100000
int price_exp,sales_exp; //政府对某种商品的预期价,预期价所对应的销售量
int price[MAX_SIGH],sales[MAX_SIGH],sz; //商品成本,成本价销售时的销售量,商品个数(数组真实大小)
int sales_minus; //在已知的最高单价外每升高一块钱将减少的销量

//题目:相邻价位间销量的变化是线性的 所以可以通过单位销量差求得 价格--销量 表
void supple(int id_price_high,int id_price_low){ //求得(较低价格,较高价格)中的 价格--销量 数据并存入数组中
    int price_high=price[id_price_high],price_low=price[id_price_low]; //求得较高价格与较低价格
    int minus_sales_per=(sales[id_price_high]-sales[id_price_low])/(price_high-price_low); //求出单位销量差
    sz=id_price_low; //更改数组大小,准备存入两数中间对应价格的销量
    for(int pa_price=price_low+1;pa_price<=price_high;pa_price++){ //存入两数中间对应价格的销量
        sz++;
        price[sz]=pa_price;
        sales[sz]=sales[sz-1]+minus_sales_per; 
    }
}

void input(){
    scanf("%d",&price_exp); //读入政府对某种商品的预期价
    for(sz=1;;sz++){
        scanf("%d%d",&price[sz],&sales[sz]); //price[1]是成本,sales[1]是成本对应的销售量
        if(price[sz]==-1&&sales[sz]==-1) break; //(-1,-1)表示读入结束,退出循环
        if(sz==1) continue; //只有1个数,不符合更新的条件,跳过
        if(price[sz]-price[sz-1]>1) supple(sz,sz-1); //更新:求得两数中间对应价格的销量并存入数组中
    }
    sz--; //去除(-1,-1)的数据
    scanf("%d",&sales_minus); //读入在已知的最高单价外每升高一块钱将减少的销量
}

void expand(){ //求得所有价格>给定最高价位的 价格--销量 数据
    for(;sales[sz]>0;){
        ++sz;
        price[sz]=price[sz-1]+1;
        sales[sz]=sales[sz-1]-sales_minus;
    }
    sz--; //去除<0的数据
}

int ac_sales_exp(){ //求得预期价格所对应的销量
    for(int i=0;i<sz;i++)
        if(price_exp==price[i]) return sales[i];
    return 0;
}

bool is_profit_exp_max(int pa_profit_tot_exp,int pa_change){ //求得政府预期的总利润是否最大
    for(int i=0;i<sz;i++){
        int profit_tot=sales[i]*(price[i]-price[1]+pa_change); //总利润=销量*(单位商品价格-单位商品成本(-税金or+补贴)
        if(profit_tot>pa_profit_tot_exp) return false;
    }
    return true;
}

void traverse(){ //对税金/补贴从0开始遍历,求得其最小值
    for(int i=1,change=0;;i++){ //change为负代表税金,为正代表补贴
        int profit_tot_exp=sales_exp*(price_exp-price[1]+change); //总利润=销量*(单位商品价格-单位商品成本(-税金or+补贴)
        if(is_profit_exp_max(profit_tot_exp,change)) {printf("%d",change);exit(0);} //如果政府预期的总利润是最大,则输出税金/补贴,结束程序

        //以正负的方式分别计算税金和补贴
        if(i&1) change=abs(change)+1; //如果i是奇数,则change扩大一位
        change*=-1; //将补贴换成税金
    }
}

int main(){
    //求得 价格--销量 表
    input(); //读入数据并求得所有价格<=给定最高价位的 价格--销量 数据
    expand(); //求得所有价格>给定最高价位的 价格--销量 数据

    sales_exp=ac_sales_exp(); //求得预期价格所对应的销量
    traverse(); //对税金/补贴从0开始遍历,求得其最小值

    return 0;
}

题目序号:0196
分级依据:牛客竞赛
参考资料:洛谷题解 洛谷题目

你可能感兴趣的:(NOIP2000 税收与补贴问题)