BZOJ5018: [Snoi2017]英雄聯盟
阿新 • • 發佈:2019-01-19
思路 sca 決定 們的 應該 得到 怎麽 希望 -i
Description
正在上大學的小皮球熱愛英雄聯盟這款遊戲,而且打的很菜,被網友們戲稱為「小學生」。現在,小皮球終於受不
了網友們的嘲諷,決定變強了,他變強的方法就是:買皮膚!小皮球只會玩N個英雄,因此,他也只準備給這N個英
雄買皮膚,並且決定,以後只玩有皮膚的英雄。這N個英雄中,第i個英雄有Ki款皮膚,價格是每款CiQ幣(同一個
英雄的皮膚價格相同)。為了讓自己看起來高大上一些,小皮球決定給同學們展示一下自己的皮膚,展示的思路是
這樣的:對於有皮膚的每一個英雄,隨便選一個皮膚給同學看。比如,小皮球共有5個英雄,這5個英雄分別有0,0,
3,2,4款皮膚,那麽,小皮球就有3*2×4=24種展示的策略。現在,小皮球希望自己的展示策略能夠至少達到M種,
請問,小皮球至少要花多少錢呢?
Input
第一行,兩個整數N,M
第二行,N個整數,表示每個英雄的皮膚數量Ki
第三行,N個整數,表示每個英雄皮膚的價格Ci
共 10 組數據,第i組數據滿足:N≤max(5,(log2i)^4) M≤10^17,1≤Ki≤10,1≤Ci≤199。保證有解
Output
一個整數,表示小皮球達到目標最少的花費。
Sample Input
3 24
4 4 4
2 2 2
Sample Output
18
Solution
我怎麽這麽菜啊。啥dp都不會寫,只會抄題解,要練練思維了qwq
我怎麽就看不出來這個是個背包呢
會發現n,k,c都很小,m卻很大,所以dp狀態裏面應該不會有方案,應該會有價格
所以可以設\(f[i][j]\)表示買到第\(i\)個英雄,一共花了\(j\)元可以得到的最大展示數目
轉移直接暴力枚舉現在買了多少個英雄,再暴力枚舉之前花了多少錢就好了。
有一個很實用的小技巧(來自另外一篇題解):因為是一個判定問題,所以可以將轉移對m取min,防止遇到高精度。
#include <bits/stdc++.h> using namespace std; #define N 100010 #define ll long long ll f[200][N]; //表示買到i時花費為j的最大展示數 int sum, n, a[N]; ll m; int main() { scanf("%d%lld", &n, &m); for(int i = 1; i <= n; ++i) scanf("%d", &a[i]); f[0][0] = 1; for(int i = 1, c; i <= n; ++i) { scanf("%d", &c); for(int j = 0; j <= sum; ++j) f[i][j] = f[i - 1][j]; for(int j = 1; j <= a[i]; ++j) { for(int k = j * c; k <= sum + j * c; ++k) { f[i][k] = min(m, max(f[i][k], 1ll * f[i - 1][k - j * c] * j)); } } sum += c * a[i]; } for(int i = 0; i <= sum; ++i) { if(f[n][i] >= m) { printf("%d\n", i); return 0; } } }
BZOJ5018: [Snoi2017]英雄聯盟