1. 程式人生 > >#10004. 「一本通 1.1 例 5」智力大沖浪

#10004. 「一本通 1.1 例 5」智力大沖浪

【題目描述】

小偉報名參加中央電視臺的智力大沖浪節目。本次挑戰賽吸引了眾多參賽者,主持人為了表彰大家的勇氣,先獎勵每個參賽者 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 
*/ 

程式碼就是這樣,要是有大佬發現什麼錯誤,或者有什麼大佬感覺怪怪的,望指出。