#10004. 「一本通 1.1 例 5」智力大沖浪
阿新 • • 發佈:2018-11-21
【題目描述】
小偉報名參加中央電視臺的智力大沖浪節目。本次挑戰賽吸引了眾多參賽者,主持人為了表彰大家的勇氣,先獎勵每個參賽者 m 元。先不要太高興!因為這些錢還不一定都是你的?!接下來主持人宣佈了比賽規則:
首先,比賽時間分為 n個時段,它又給出了很多小遊戲,每個小遊戲都必須在規定期限 ti前完成。如果一個遊戲沒能在規定期限前完成,則要從獎勵費 m元中扣去一部分錢 wi,wi為自然數,不同的遊戲扣去的錢是不一樣的。當然,每個遊戲本身都很簡單,保證每個參賽者都能在一個時段內完成,而且都必須從整時段開始。主持人只是想考考每個參賽者如何安排組織自己做遊戲的順序。作為參賽者,小偉很想贏得冠軍,當然更想贏取最多的錢!注意:比賽絕對不會讓參賽者賠錢!
【輸入格式】
輸入共四行。
第一行為 m,表示一開始獎勵給每位參賽者的錢;
第二行為 n,表示有 n 個小遊戲;
第三行有 n 個數,分別表示遊戲 1 到 n 的規定完成期限;
第四行有 n個數,分別表示遊戲 1到 n不能在規定期限前完成的扣款數。
【輸出格式】
輸出僅一行,表示小偉能贏取最多的錢。
【樣例輸入】
10000
7
4 2 4 3 1 4 6
70 60 50 40 30 20 10
【樣例輸出】
9950
【資料範圍與提示】
對於 100% 的資料,有 n≤500,1≤ti≤n。
思路:說實在的,我剛開始真的被這個題目給搞蒙了,因為題目沒有說清楚,但是其實要是理清楚了題目的話這道題真的很簡單很簡單,其實就是一個稍微複雜一點的判斷這個數用沒用過。我先來分析一下題目:有n個遊戲,每個遊戲都有限定的時間和沒有完成的時候的相應的處罰,求最小的處罰(這個就是題目最最最簡單的分析。)然後,這樣之後,我們第一個想到的是要編目錄(也就是結構體),因為我們要求最小的,既然是最小最大這一類的,自然要排序,這樣才能使我們在篩選的時候更加的方便。可能有一個不容易想到,那就是在排序的時候,我們要按照處罰從大到小排序,為什麼要這樣排序呢?因為我們從大到小的話,就會使我們在前面的判斷的時候可以直接把最大的處罰先去掉,然後到後面不可行的時候,就是最小的處罰,這樣才可以使我們所得到的處罰最小。 大致的思路理解了嗎?噢噢噢噢還有一個重點,就是我們在判斷當前的這個時間期限可不可以用的時候,一定不可以魯莽的判斷表層的時間,而是要深入判斷從當前的這個表層時間到時間為1的時候,只有全部都不可以,才是這的不可以。
【程式碼實現,註釋寫的很詳細,快讀不解釋我發過部落格的】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read()//日常快讀
{
char c=getchar();
int x=0,f=1;
while(c<48 || c>57)
{
if(c=='-') f=-1;
c=getchar();
}
while(c>=48 && c<=57)
{
x=x*10+c-48;
c=getchar();
}
return x*f;
}
struct node
{
int t,w;//t表示時間期限 //w表示罰款
}a[110000];
bool cmp(node n1,node n2)
{
return n1.w>n2.w;//按罰款額從大到小排序
}
bool bk=false;//這個是判斷要不要罰款,一開始初始化全部都要罰款
bool v[110000];//這個是用來判斷當前這個時間期限的所有期限要不要罰款
int main()
{
memset(v,true,sizeof(v));//初始化全部都不用罰款
int m,n; m=read(); n=read();
for(int i=1;i<=n;i++) a[i].t=read();
for(int i=1;i<=n;i++) a[i].w=read();
sort(a+1,a+n+1,cmp);//按罰款額的大小進行排序
for(int i=1;i<=n;i++)
{
bk=false;//最開始要罰款
for(int j=a[i].t;j>=1;j--)
/*
這個是按時間期限來列舉判斷
因為我們要按時間的完成度來罰款
所以自然就是以時間來罰款的啦
還有一個就是如果我要知道這一種情況到底是不是不可以的
那我就一定要把這個時間的每一個時間點都給計算一遍
如果每一次都不可以的話,說明這個任務就是不能完成的
*/
{
if(v[j]==true)
/*
如果這一步進入不了的話
那就繼續上面的j的迴圈,而不是退出到i的迴圈
這樣迴圈是為了對當前的這一個遊戲公平
說當前的遊戲不能做的話,
一定是因為他的所有期限都完成不了,才可以罰款
所以當前的這一個不行不代表前面的不行
比如說:期限為4的話,4我們記錄過不行,
但是3,2,1我們沒有記錄那就不能說我們當前的這種情況要完成不了,
就不能說當前的這一個遊戲我們要罰款
*/
{
v[j]=false;
/*
就把當前這種方案變為false,表示記錄過
下一次在出現的話就要判斷為false,也就是不能用
*/
bk=true;//然後bk=true,說明不用罰款
break;//退出迴圈,到下面判斷到底需不需要罰款
}
}
if(bk==false) m-=a[i].w;
/*
注意這一步不是最後判斷的,而是在上面的break之後
就立刻判斷,如果經過了上面那一步不成立的話
就說明當前的這一種方式不可以走,所以就要罰款
*/
}
printf("%d\n",m);//剩下的錢就是可以拿到的最多的錢
return 0;
}
/*
樣例輸入
10000
7
4 2 4 3 1 4 6
70 60 50 40 30 20 10
樣例輸出
9950
樣例解釋:第5個遊戲和第6個遊戲不能完成
到第五個遊戲的時候,1到4這四個期限在v數組裡面都已經是false
所以第五個的1就直接false了,就要罰款30元
然後到第六個遊戲的時候,1到4這四個期限還是不行的
所以就直接false掉了,就要罰款20元
第七個遊戲就可以,因為期限為6在前面沒有出現過
所以就是10000-30-20=9950
*/
程式碼就是這樣,要是有大佬發現什麼錯誤,或者有什麼大佬感覺怪怪的,望指出。