BestCoder Round #59 (div.2)

SDOI

 
 Accepts: 306
 
 Submissions: 993
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 131072/131072 K (Java/Others)
問題描述
一年一度的全國信息學奧林匹克競賽(NOI)即將舉辦,SD省組織進行了一次省隊選拔,一共有 n (n \leq 100)n(n100)名選手參加了這次省隊選拔。
今年,SD省的省隊名額爲 m (m \leq 50)m(m50) 人,即,今年的SD省隊有 mm 名隊員。

按照慣例,SD省的省隊選拔有兩輪比賽,依次爲“Round1”和“Round2”,每個Round的滿分爲 300300 分。
所有 n 名選手都參加了Round1和Round2,現在每名選手Round1和Round2的“原始得分”已經確定。SD省的省隊選拔採用標準分計算方式,即,設某個Round的最高原始得分爲 xx 分(保證每輪比賽都不會全場零分,即x>0x>0),那麼此Round每名選手的“相對得分”爲: 這名選手此Round的原始得分* (300 / x)(300/x)。
所有選手的Round1和Round2的相對得分計算完畢後,將計算每名選手的“最終成績”。一名選手的最終成績爲:這名選手的Round1相對得分* 0.30.3 + 這名選手的Round2相對得分* 0.70.7。非常和諧的是,保證不存在兩名選手的最終成績相等。

所有選手的最終成績計算完畢後,將會按照以下規則選出省隊隊員:
爲了鼓勵女生參加信息學奧賽及相關活動,在有女選手參加省隊選拔的情況下,省隊中有一個固定的女選手名額。
1)若沒有女選手參加省隊選拔,則最終成績最高的 mm 位選手進入省隊。
2)若有女選手參加省隊選拔,則最佳女選手(女選手中最終成績最高者)進入省隊,其餘的選手(男選手和最佳女選手之外的女選手)中成績最高的 m-1m1 位選手進入省隊。

現在已經到了省隊選拔的最後階段,請你編寫一個程序,根據輸入的所有選手的信息(姓名,性別,Round1和Round2的原始得分),輸出進入省隊的選手的姓名,輸出的姓名按照省隊隊員的最終成績降序(從高到低)排列。
輸入描述
第一行爲一個整數 T(T \leq 100)T(T100),表示數據組數。
接下來有TT組數據。
對於每組數據,第一行有兩個正整數 nnm (n \geq m)m(nm),分別表示參加省隊選拔的選手人數和省隊的名額數。接下來有 nn 行,每行輸入一名選手的信息,共4項,依次爲姓名(一個長度不超過20的字符串,只包含數字和大小寫英文字母)、性別(一個字符串,爲"male"[男]或"female"[女])、Round1原始得分(小於等於300的非負整數)和Round2原始得分(小於等於300的非負整數)。各項之間用空格隔開。
輸出描述
對於每組數據,先輸出一行"The member list of Shandong team is as follows:"(不帶引號),接下來輸出mm行,每行爲一名省隊隊員的姓名,按省隊隊員的最終成績降序(從高到低)排列。
輸入樣例
2
10 8
dxy male 230 225
davidwang male 218 235
evensgn male 150 175
tpkuangmo female 34 21
guncuye male 5 15
faebdc male 245 250
lavender female 220 216
qmqmqm male 250 245
davidlee male 240 160
dxymeizi female 205 190
2 1
dxy male 300 300
dxymeizi female 0 0
輸出樣例
The member list of Shandong team is as follows:
faebdc
qmqmqm
davidwang
dxy
lavender
dxymeizi
davidlee
evensgn
The member list of Shandong team is as follows:
dxymeizi
Hint
第一組數據:第一輪最高分爲250250,所以每個人的成績都要乘(300/250)=1.2(300/250)=1.2,第二輪最高分也爲250250,每個人的成績也要乘1.21.2。
每個人的最終成績按降序排如下
faebdc 298.20
qmqmqm 295.80
davidwang 275.88
dxy 271.80
lavender 260.64
dxymeizi 233.40
davidlee 220.80
evensgn 201.00
tpkuangmo 29.88
guncuye 14.40
有女選手參加,最佳女選手lavender進入省隊,其他分最高的77人按名次排列進入省隊

第二組數據:有女選手參加,最佳女選手dxymeizi進入省隊,dxy雖然分高,但不能進隊。
思路:用結構體按照思路無腦敲即可,拼的是手速。按照最終成績排名,如果無女生,則直接輸出m名
有女生的情況,按順序輸出m-1名,如果最佳女生在這m-1名裏,那麼直接輸出第m名,否則輸出這麼最佳女生。
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=105;
struct Node
{
    string name;
    string x;
    int r1,r2;
    double temp1,temp2,sum;
};
Node peo[MAXN];
bool cmp(Node a,Node b)
{
    return a.sum>b.sum;
}
int main()
{
    int t,n,m;
    cin>>t;
    while(t--)
    {
        int g=0,x1=0,x2=0;
        cin>>n>>m;
        for(int i=0;i<n;i++)
        {
            cin>>peo[i].name;
            cin>>peo[i].x;
            if(peo[i].x=="female")
            {
                g++;
            }
            cin>>peo[i].r1;
            x1=(x1>peo[i].r1?x1:peo[i].r1);
            cin>>peo[i].r2;
            x2=(x2>peo[i].r2?x2:peo[i].r2);
        }
        for(int i=0;i<n;i++)
        {
            peo[i].temp1=peo[i].r1*(300/(x1*1.0));
            peo[i].temp2=peo[i].r2*(300/(x2*1.0));
            peo[i].sum=peo[i].temp1*0.3+peo[i].temp2*0.7;
        }
        sort(peo,peo+n,cmp);
        cout<<"The member list of Shandong team is as follows:"<<endl;
        if(g>0)
        {
            int index;
            for(int i=0;i<n;i++)
            {
                if(peo[i].x=="female")
                {
                    index=i;
                    break;
                }
            }
            if(index>=m)
            {
                for(int i=0;i<m-1;i++)
                {
                    cout<<peo[i].name<<endl;
                }
                cout<<peo[index].name<<endl;
            }
            else
            {
                for(int i=0;i<m;i++)
                {
                    cout<<peo[i].name<<endl;
                }
            }
        }
        else
        {
            for(int i=0;i<m;i++)
            {
                cout<<peo[i].name<<endl;
            }
        }
    }
    return 0;
}


Reorder the Books

 
 Accepts: 252
 
 Submissions: 693
 Time Limit: 4000/2000 MS (Java/Others)
 
 Memory Limit: 131072/131072 K (Java/Others)
問題描述
dxy家收藏了一套書,這套書叫《SDOI故事集》,《SDOI故事集》有n(n\leq 19)n(n19)本,每本書有一個編號,從11號到nn號。
dxy把這些書按編號從小到大,從上往下摞成一摞。dxy對這套書極其重視,不允許任何人動這套書。
有一天Evensgn到dxy家玩,dxy因爲和妹子有約會,就讓Evensgn自己待在他家。Evensgn對這套書非常好奇,偷偷的看了一下,結果發現這裏面竟然有當年小E和小Q的故事。Evensgn看得出神,結果把一摞書的順序打亂了。
眼看着dxy就要回來了,Evensgn需要儘快把這摞書恢復到原先排好序的狀態。由於每本書都非常重,所以Evensgn能做的操作只有把一本書從書堆中抽出來,然後把這本書放到書堆的頂部。
給你打亂的書的順序,你能幫Evensgn算算最少需要幾次上述的操作,他才能把這套書恢復順序?假如你能算出來的話,Evensgn答應送給你一本他簽名的書《SDOI故事集9:小E的故事》
輸入描述
輸入包含多組數據。
第一行包含一個正整數T(T\leq 30)T(T30)表示數據組數。
對於每組數據,第一行爲一個正整數nn表示這套《SDOI故事集》中有多少本書。
接下來一行nn個用空格分開的正整數,表示Evensgn打亂後的這摞書的書號順序(從上往下)。
輸出描述
對於每組數據,輸出一行一個整數,表示Evensgn最少需要幾次操作才能講書恢復順序。
輸入樣例
2
4
4 1 2 3
5
1 2 3 4 5
輸出樣例
3
0
Hint
對於第一組數據,我們先把33號書放到最上面,接着操作22號書,最後操作11號書,(4,1,2,3)\rightarrow (3,4,1,2)\rightarrow(2,3,4,1)\rightarrow(1,2,3,4)(4,1,2,3)(3,4,1,2)(2,3,4,1)(1,2,3,4),這樣就有序了
對於第二組數據,這摞書本來就有序了,所以不需要任何操作
n>15n>15的數據不超過1010

思路:保持最終順序中後面的儘量少移動或者不移動,即是最終順序從後面向開始順序的後面進行匹配,
如果匹配不成功,開始序列向前移動,如果匹配成功,最終順序向前移動(即是匹配其前一個)。
使得儘量多可以匹配到。最終剩下的未被匹配的元素依次移動到隊頭,就可以以最少的步數
到達最終順序。
#include<iostream>
using namespace std;
const int MAXN = 25;
int book[MAXN];
int main()
{
	int t, n;
	cin >> t;
	while (t--)
	{
		int i, j;
		cin >> n;
		for (i = 1; i <= n; i++)
		{
			cin >> book[i];
		}
		for (i = j = n; i > 0; i--)
		{
			if (book[i] == j)
			{
				j--;
			}
		}
		cout << j << endl;
	}
	//system("pause");
	return 0;
}

The Highest Mark

 
 Accepts: 32
 
 Submissions: 193
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 131072/131072 K (Java/Others)
問題描述
2045年的SD省隊選拔,賽制和三十年前已是完全不同。一場比賽的比賽時間有 tt 分鐘,有 nn 道題目。
第 ii 道題目的初始分值爲 A_i(A_i \leq 10^{6})Ai(Ai106) 分,之後每過一分鐘這道題目的分值會減少 B_iBi 分,並且保證到比賽結束時分值不會減少爲負值。比如,一個人在第 xx 分鐘結束時做出了第 ii 道題目,那麼他/她可以得到 A_i - B_i * xAiBix 分。
若一名選手在第 xx 分鐘結束時做完了一道題目,則他/她可以在第 x+1x+1 分鐘開始時立即開始做另一道題目。
參加省隊選拔的選手 dxy 具有絕佳的實力,他可以準確預測自己做每道題目所要花費的時間,做第 ii 道需要花費 C_i(C_i \leq t)Ci(Cit) 分鐘。由於 dxy 非常神,他會做所有的題目。但是由於比賽時間有限,他可能無法做完所有的題目。他希望安排一個做題的順序,在比賽結束之前得到儘量多的分數。
輸入描述
第一行爲一個正整數 T(T \leq 10)T(T10),表示數據組數(n>200n>200的數據不超過55組)。
對於每組數據,第一行爲兩個正整數 n (n \leq 1000)n(n1000)t (t \leq 3000)t(t3000), 分別表示題目數量和比賽時間。接下來有 nn 行,每行 33 個正整數依次表示 A_i, B_i, C_iAi,Bi,Ci,即此題的初始分值、每分鐘減少的分值、dxy做這道題需要花費的時間。
輸出描述
對於每組數據輸出一行一個整數,代表dxy這場比賽最多能得多少分
輸入樣例
1
4 10
110 5 9
30 2 1
80 4 8
50 3 2
輸出樣例
88
Hint
dxy先做第二題,再做第一題,第一題得分爲110-5*(1+9)=601105(1+9)=60,第二題得分爲30-2*1=283021=28,總得分爲8888,其他任何方案的得分都小於8888


思路:貪心+DP,剛開始按照每題解決時間來貪心【按c遞增排序】,初始AC了,但是終判WA了,看了題解發現按每道題目扣分速度與做題時間的比值排序,按照比值從大到小做題。

首先我們考慮,假如我們已經確定了要做哪些題目,按什麼順序做這些題目最好。

假設已經確定了要做其中的mm道題,某一個方案中做題的順序是依次做x_{1},x_{2}\rightarrow{x}_{m}x1,x2xm,那麼對於這個方案中任意的相鄰兩項{x}_{i}xi,{x}_{i+1}xi+1,考慮交換這兩項的順序,方案是否會變得更優,交換方案中的相鄰兩項,只會對這兩道題的得分有影響,對其餘的題目不會產生影響。

如果不交換這兩項,損失的分數是 C_{x_{i}} * B_{x_{i+1}} + KCxiBxi+1+K,如果交換這兩項,損失的分數是C_{x_{i+1}} * B_{x_{i}} + KCxi+1Bxi+K (K是一個常數) 所以只需要判斷是否 C_{x_{i}} * B_{x_{i+1}} \leq C_{x_{i+1}} * B_{x_{i}} + KCxiBxi+1Cxi+1Bxi+K,如果此不等式成立,那麼應該交換這兩項。對上式移項得 B_{x_{i+1}} / C_{x_{i+1}} > B_{x_{i}} / C_{x_{i}}Bxi+1/Cxi+1>Bxi/Cxi 。所以對於一個確定的題目集合,做題的最優順序只與每道題目的B_i / C_iBi/Ci有關,按每道題目扣分速度與做題時間的比值排序,按照比值從大到小做題。

因此我們先對所有的題目按照這個比值進行排序,接下來,只要按照排好的順序,選擇做哪些題目就可以了。這相當於一個簡單的“揹包問題”,使用動態規劃來解決。{dp}_idpi表示恰好用了ii分鐘的最高得分。狀態轉移方程爲{dp}_i = \max_{1\leq j\leq n}{dp}_{i-C_j} + A_j - (i * B_j)dpi=max1jndpiCj+Aj(iBj)

最終答案是\max_{0 \leq i \leq t}{dp_i}max0itdpi


#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 1010;
const int MAXT = 3010;
struct Node
{
	int a, b, c;
	double s;
};
Node pos[MAXN];
int dp[MAXT];
bool cmp(Node a, Node b)
{
	return a.s>b.s;
}
int my_max(int a, int b)
{
	return a>b ? a : b;
}
int main()
{
	int ans, n, t;
	cin >> ans;
	while (ans--)
	{
		cin >> n >> t;
		for (int i = 0; i < n; i++)
		{
			cin >> pos[i].a >> pos[i].b >> pos[i].c;
			pos[i].s = (pos[i].b*1.0) / pos[i].c;
		}
		sort(pos, pos + n, cmp);
		memset(dp, 0, sizeof(dp));
		for (int i = 0; i<n; i++)
		{
			for (int j = t; j >= pos[i].c; j--)
			{
				dp[j] = my_max(dp[j], dp[j - pos[i].c] + my_max(0,(pos[i].a - pos[i].b*j)));
			}
		}
		int total = 0;
		for (int i = 0; i <= t; i++)
		{
			total = my_max(total,dp[i]);
		}
		cout << total << endl;
	}
	//system("pause");
	return 0;
}



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