1. 程式人生 > >BZOJ5018: [Snoi2017]英雄聯盟

BZOJ5018: [Snoi2017]英雄聯盟

思路 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]英雄聯盟