BuringStraw

BuringStraw

太年輕

太年轻了#

今天做了一套模擬題,成功爆 20。

這套題出題人全程暴力 %,今朝笑話講的好,——。

但我笑著笑著就笑不出來了。

然後就爆 20 了。

在眾多毒瘤題的包圍下來一套簡單的小水題,可以愉悅身心、增加信心......

這麼簡單地一套題相信大家都已經輕鬆 AK 了,不過 CSP-S 可就不一定也這麼水了,希望大家在 CSP-S 的第一年也能 RP++,虐場快樂

——出題人

我:?

這是第一題,後兩道太NaN

題目#

大學選課真的是一件很苦惱的事呢!

Marco:“我要兩年畢業!我要選盡量多的學分!這些課統統選上!”

長者:"你啊,太年輕!你看看作業量,你做的完嗎?"

Marco(笑容逐漸消失.gif):” 那可咋整啊?“

長者:" 還能咋整?退課唄!“

已知 Marco 選了 $N (1 \leq N \leq 500)$ 門課,每門課有學分 $w_i$ ,勞累度 $v_i$ 和掛科概率 $p_i$ ;

其中,$w_i$ 為 $[1,5]$ 範圍內的一個正整數,$v_i$ 是 int 範圍內正整數, $p_i$ 是 $[0,1]$ 範圍內小數;

現在 Marco 想退掉某些課使得自己的勞累度盡量小,但是,如果 Marco 的學分總數達不到給定的 $MINX$,他會被退學。

Marco 想知道,在期望學分大於等於 $MINX$ 的情況下,他的最小勞累度是多少。

注意:如果一門課掛科,Marco 將付出 $v_i$ 的勞累度但是無法獲得相應學分;否則,Marco 將付出 $v_i$ 的勞累度並收獲 $w_i$ 的學分。

輸入格式#

第一行一個正整數 $N$ 表示課程數量

接下來 $N$ 行,每行空格分開的 $3$ 個數 $w_i,v_i$ 和 $p_i$ ,含義如題面所述

最後一行一個正整數 $MINX$ 表示所需最小學分。

輸出格式#

一行一個正整數表示最小勞累度。

數據範圍#

本題共 10 個測試點,每個測試點 10 分。

對於 $10%$ 的數據,$1 \leq N \leq 10$

對於 $30%$ 的數據,$1 \leq N \leq 20$

對於另外 $20%$ 的數據,$p_i=0$

對於 $100%$ 的數據,

$1 \leq N \leq 500$ ,

$w_i$ 是正整數且 $1 \leq wi \leq 5$,

$p_i$ 最多包含 $2$ 位小數且 $0 \leq pi \leq 1$,

$v_i$ 是 int 範圍內正整數.

保證全選的情況下 Marco 不會被退學。

輸出時每行末尾的多餘空格,不影響答案正確性

样例输入#

2
1 233 0
2 1 0.5
1

样例输出#

1

样例解释#

只選擇第 $2$ 門課,期望學分為 $2*0.5=1$ 分,勞累程度為 1

思路#

最開始想的是f[i][j]表示考慮到了第i門課,勞累度為j時得的最大分數

然後發現j的範圍太大。。。

又想著拿f[i][j]表示考慮到第i門課,期望得分j的最小勞累度

但期望得分是小數啊!!

然後瞎雞兒寫了個n<20,dfsn>20,瞎Dp

此題爆零。

賽後看題解:

UTOOLS1572264681454.png

UTOOLS1572264715976.png

好,好的!

還有一個卡精度的問題。

借一下唢呐大佬的圖

UTOOLS1572264861444.png

啥??

然後我發現

100 - p * 100也是不行的

加上0.01或者round(100 - p * 100)都能過??

算了算了,以後記得用 round。

代碼#

就這麼幾行。。。

#include <cstdio>
#include <algorithm>
#include <cmath>

const int MAXN = 505;

int w[MAXN], v[MAXN];
long long f[MAXN * MAXN];
int n;
int minx;
int maxW = 0;
long long ans = (1ll<<60ll);

int main (void) {
	freopen("young.in", "r", stdin);
	freopen("young.out", "w", stdout);
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i) {
		double p;
		scanf("%d%d", w + i, v + i);
		scanf("%lf", &p);
		w[i] *= round(100 - p * 100);
		maxW += w[i];
	}
	scanf("%d", &minx);
	minx *= 100;
	for (int i = 1; i <= maxW; ++i) {
		f[i] = (1ll<<60ll);
	}
	int sum = 0;
	for (int i = 1; i <= n; ++i) {
		sum += w[i];
		for (int j = sum; j >= w[i]; --j) {
			f[j] = std::min(f[j], f[j - w[i]] + v[i]);
		}
	}
	for (int i = minx; i <= sum; ++i) {
		ans = std::min(ans, f[i]);
	}
	printf("%lld\n", ans);
	return 0;
}
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。