題目鏈接: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 = -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)