洛谷P1023 稅收與補貼問題 解題全過程

題目鏈接:https://www.luogu.org/problem/P1023
實不相瞞,我連題目都沒看懂,看完這個講解才明白的。。。
https://www.luogu.org/discuss/show/119090
再吐槽一句:此題數據好弱。。。
思路:將給的數據放進一個結構體,第零個位置是成本價,後邊的全是樣例給的數據,然後按照單價進行排序,小在上大在下,再像講解裏那樣把剩餘的數據給補齊。(數據的準備就完成了)接下來按照循環去求每個點能獲得的利潤是不是政府所期望的價值,符合就輸出
最開始寫的

#include <cstdio>
#include <cstring>
#include <iostream>//C++頭文件
#include <algorithm>//算法頭文件,內置sort(),max()等函數。
using namespace std;
int seifu;//政府的期望價格
int sukonai;//每提高一塊錢減少的銷量
int sit=0;//to ki ro ku num[] 去記錄數組當前有數據的下標
int ans;
struct all_case
{
    int price;//單價
    int num;//銷量
    int money;//此單價獲得的利潤
}a[200000];
void find()
{
    while(1)
    {
        int tmp = a[sit].num - sukonai;
        if(tmp < 0)break;
        sit++;
        a[sit].price = a[sit-1].price + 1;
        a[sit].num = tmp;
    }
}
bool cmp(const all_case &_a,const all_case &_b){return _a.price < _b.price;}
void init()
{
    //freopen("1.in","r",stdin);
    scanf("%d",&seifu);
    scanf("%d%d",&a[0].price,&a[0].num);
    while(1)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        if(x == -1 && y == -1)break;
        a[++sit].price = x;
        a[sit].num = y;
    }
    scanf("%d",&sukonai);
}
bool done(int fz)
{
   //先把每個價格的利潤算出來,符合就直接輸出,不符合就重新開始
    int i;
    int maxx = 0;
    int maxx_p=0;
    for(i=1;i<=sit;i++)
        a[i].money = (a[i].price - a[0].price + fz)*a[i].num;
    for (i=1;i<=sit;i++)
        if(maxx < a[i].money){maxx = a[i].money; maxx_p=i;}
    if(a[maxx_p].price == seifu)return 1;
    return 0;
}
int main()
{
    int i;
    init();
    sort(a+1,a+sit+1,cmp);
    find();//把樣例沒給出的且銷量不爲零的單價全部算出來
    //for(i=0;i<=sit;i++)printf("%d %d\n",a[i].price,a[i].num);
    for(i=0;i<=100000;i++)
    {
        if(done(i)){printf("%d",i);return 0;}
        if(i==0)continue;
        if(done(-i)){printf("%d",-i);return 0;}
    }
    return 0;
}

在這裏插入圖片描述
下載第四個測試點樣例發現
在這裏插入圖片描述
原因:只考慮到比當前數據還大的單價,沒想到成本價和題目所給的最小單價之間可能不是連貫的。
添加代碼:

void find_again()
{
    int i;
    //28  30   成本價28 最小30的話只需要補充一次就行了
    int cnt = a[1].price - a[0].price - 1;
    //先行補充一次,後面新添加的數據從該數據的後面添加,方便
    sit++;
    a[sit].price = a[0].price + 1;
    a[sit].num = a[0].num -sukonai;
    for(i=1;i<cnt;i++)
    {
        int tmp = a[sit].num - sukonai;
        if(tmp <= 0)return;
        sit++;
        a[sit].price = a[sit-1].price + 1;
        a[sit].num = tmp;
    }
}

sort(a+1,a+sit+1,cmp);
find();//把樣例沒給出的且銷量不爲零的單價全部算出來
if(a[0].price + 1 != a[1].price)find_again();//如果成本價和最小單價不連貫,那就去補齊

結果答案是-21不是樣例點給的-20。
測試後發現。當 i = -20 時:4010和4011的利潤是一樣的,而我們done函數的規則是找到當前最大值的時候將當前的單價記錄下來
i = -20
i = -21時
在這裏插入圖片描述
解決方法:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int seifu;
int sukonai;
int sit=0;//to ki ro ku num[]
int ans;
struct all_case
{
    int price;
    int num;
    int money;
}a[200000];
void find()
{
    while(1)
    {
        int tmp = a[sit].num - sukonai;
        if(tmp <= 0)break;
        sit++;
        a[sit].price = a[sit-1].price + 1;
        a[sit].num = tmp;
    }
}
bool cmp(const all_case &_a,const all_case &_b){return _a.price < _b.price;}
void init()
{
    freopen("1.in","r",stdin);
    scanf("%d",&seifu);
    scanf("%d%d",&a[0].price,&a[0].num);
    while(1)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        if(x == -1 && y == -1)break;
        a[++sit].price = x;
        a[sit].num = y;
    }
    scanf("%d",&sukonai);
}
void find_again()
{
    int i;
    //28  30   
    int cnt = a[1].price - a[0].price - 1;
    sit++;
    a[sit].price = a[0].price + 1;
    a[sit].num = a[0].num -sukonai;
    for(i=1;i<cnt;i++)
    {
        int tmp = a[sit].num - sukonai;
        if(tmp <= 0)return;
        sit++;
        a[sit].price = a[sit-1].price + 1;
        a[sit].num = tmp;
    }
}
bool done(int fz)
{
    //先把每個價格的利潤算出來,符合就直接輸出,不符合就重新開始缺少一組銷量增加的數據 
    int i;
    int maxx = 0;
    int a_serifu_money;//計算的時候順便將政府期望的價格算出來,和最大值進行對比
    for(i=1;i<=sit;i++)
    {
        a[i].money = (a[i].price - a[0].price + fz)*a[i].num;
        if(a[i].price == seifu)a_serifu_money = a[i].money;//find it
    }
    for(i=1;i<=sit;i++)maxx=max(maxx,a[i].money);//直接找最大值
    if(a_serifu_money == maxx)return 1;
    return 0;
}
void test()
{
    int i;
    for(i=0;i<=sit;i++)printf("%d %d %d\n",a[i].price,a[i].num,a[i].money);
}
int main()
{
    int i;
    init();
    sort(a+1,a+sit+1,cmp);
    find();
    if(a[0].price + 1 != a[1].price)find_again();
    sort(a+1,a+1+sit,cmp);
    for(i=0;i<=100;i++)//數據太弱,開100就過了
    {
        if(done(i)){printf("%d",i);return 0;}
        if(i==0)continue;
        if(done(-i)){printf("%d",-i);return 0;}
    }
    return 0;
}

補充:

sort()函數是十分方便的排序函數,省去了手寫排序的麻煩。

參數:sort(begin,end,cmp) 默認從小到大排序

cmp函數是你手寫的,可有可無。cmp相關鏈接:https://blog.csdn.net/YUK_103/article/details/99496996

max函數

max函數是個找最大值的函數,使用方法:maxx = max(a,b)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章