【bzoj5018】[Snoi2017]英雄聯盟 背包dp
阿新 • • 發佈:2017-09-07
高精 long long ros 滿足 cnblogs 判斷 using sin ont
第一行,兩個整數N,M
第二行,N個整數,表示每個英雄的皮膚數量Ki
第三行,N個整數,表示每個英雄皮膚的價格Ci
共 10 組數據,第i組數據滿足:N≤max(5,(log2i)^4) M≤10^17,1≤Ki≤10,1≤Ci≤199。保證有解
題目描述
正在上大學的小皮球熱愛英雄聯盟這款遊戲,而且打的很菜,被網友們戲稱為「小學生」。現在,小皮球終於受不了網友們的嘲諷,決定變強了,他變強的方法就是:買皮膚!小皮球只會玩N個英雄,因此,他也只準備給這N個英雄買皮膚,並且決定,以後只玩有皮膚的英雄。這N個英雄中,第i個英雄有Ki款皮膚,價格是每款CiQ幣(同一個英雄的皮膚價格相同)。為了讓自己看起來高大上一些,小皮球決定給同學們展示一下自己的皮膚,展示的思路是這樣的:對於有皮膚的每一個英雄,隨便選一個皮膚給同學看。比如,小皮球共有5個英雄,這5個英雄分別有0,0,3,2,4款皮膚,那麽,小皮球就有3*2×4=24種展示的策略。現在,小皮球希望自己的展示策略能夠至少達到M種,請問,小皮球至少要花多少錢呢?輸入
輸出
一個整數,表示小皮球達到目標最少的花費。樣例輸入
3 24
4 4 4
2 2 2
樣例輸出
18
題解
背包dp
考慮到方案數過多,無法作為狀態;而總錢數較少,所以可以以此作為狀態。
故設$f[i][j]$表示購買前$i$種皮膚,花費$j$元能夠得到的最大方案數。那麽可以直接枚舉每個皮膚購買的數量然後轉移 。
一個小trick:由於題目只要求判斷是否達到m,因此當dp值大於m時直接將其賦為m(因為方案數是單調的,只要達到了m,以後的都會達到),避免高精度。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; long long f[125][250010] , p; int v[125] , c[125]; int main() { int n , i , j , k , m = 0; scanf("%d%lld" , &n , &p); for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &v[i]); f[0][0] = 1; for(i = 1 ; i <= n ; i ++ ) { scanf("%d" , &c[i]); for(j = 0 ; j <= m ; j ++ ) f[i][j] = f[i - 1][j]; for(j = 2 ; j <= v[i] ; j ++ ) for(k = c[i] * j ; k <= m + c[i] * j ; k ++ ) f[i][k] = min(p , max(f[i][k] , f[i - 1][k - c[i] * j] * j)); m += c[i] * v[i]; } for(i = 0 ; i <= m ; i ++ ) { if(f[n][i] >= p) { printf("%d\n" , i); return 0; } } return 0; }
【bzoj5018】[Snoi2017]英雄聯盟 背包dp