ACM 训练日志记录 · 思考 · 成长 提交 / 修改记录
王梓豪 / 题目列表训练档案
导出

P1023 [NOIP 2000 普及组] 税收与补贴问题

来源:洛谷 ★ 1300

数学枚举待复习
本题活力0.28按难度、完成结果与训练证据估算

算法如山行则将至

题目描述

[NOIP 2000 普及组] 税收与补贴问题

背景

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

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

题目描述

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

  • 总利润 $=$ 单位商品利润 $\times$ 销量
  • 单位商品利润 $=$ 单位商品价格 $-$ 单位商品成本(减去税金 或者 加上补贴)

输入格式

输入的第一行为政府对某种商品的预期价;

第二行有两个整数,第一个整数为商品成本,第二个整数为以成本价销售时的销售量;

接下来若干行,每行都有两个整数,第一个为某价位时的单价,第二个为此时的销量,以一行 -1 -1 表示所有已知价位及对应的销量输入完毕;

输入的最后一行为一个单独的整数表示在已知的最高单价外每升高一块钱将减少的销量。

输出格式

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

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

说明/提示

数据范围及约定

保证输入的所有数字均小于 $10^5$。

样例解释(2023/6/22 更新)

如下图所示是输入样例所对应的价格变化图,横轴表示销售价格,纵轴表示销量。

image

根据题意,$28$ 元是商品的成本。销售价格不应该低于 $28$ 元;当销售价格大于给出的价格的最大值 $31$ 元后,按照售价每提高一元,销量降低 $15$ 计算,例如当售价为 $33$ 元时,销量为 $110-15\times (33-31)=80$。在给出来的价位之间,销量呈线性变化。

当政府给该商品补贴 $4$ 元后,企业将该商品定价为 $31$ 元时,取得的利润为 $31-28+4=7$ 元,销量为 $110$ 件,总利润为 $7\times 110=770$ 元,是企业在所有定价下能够取得的最大的总利润。此时企业的售价为政府的期望售价,因此是一个合法方案。

样例 1

输入:

31
28 130
30 120
31 110
-1  -1
15

输出:

4

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll s[100001];
ll E, c, maxP;
bool check(ll x) {
    ll best = (E - c + x) * s[E];
    for (ll i = c; i <= maxP; i++) {
        if ((i - c + x) * s[i] > best) return false;
    }
    return true;
}

int main() {
    ll sc;
    cin>>E >> c >> sc;
    s[c] = sc;
    ll lastP = c, lastS = sc;
    ll p, q;
    while (cin >> p >> q && !(p == -1 && q == -1)) {
        ll step = (q - lastS) / (p - lastP);
        for (ll j = lastP + 1; j <= p; j++)
            s[j] = lastS + step * (j - lastP);
        lastP = p;
        lastS = q;
    }
    ll de;
    cin >> de;
    maxP = lastP;
    while (s[maxP] - de > 0) {
        s[maxP + 1] = s[maxP] - de;
        maxP++;
    }
    if (E < c || E > maxP) {
        cout << "NO SOLUTION" << endl;
        return 0;
    }
    const ll LIMIT = 100000;
    for (ll k = 0; k <= LIMIT; k++) {
        if (check(k)) { cout << k << endl; return 0; }
        if (k > 0 && check(-k)) { cout << -k << endl; return 0; }
    }
    cout <<"NO SOLUTION"<< endl;
    return 0;
}