[BZOJ5018][Snoi2017]英雄联盟
试题描述
正在上大学的小皮球热爱英雄联盟这款游戏,而且打的很菜,被网友们戏称为「小学生」。现在,小皮球终于受不了网友们的嘲讽,决定变强了,他变强的方法就是:买皮肤!小皮球只会玩 (N) 个英雄,因此,他也只准备给这 (N) 个英雄买皮肤,并且决定,以后只玩有皮肤的英雄。这 (N) 个英雄中,第 (i) 个英雄有 (K_i) 款皮肤,价格是每款 (C_i) Q币(同一个英雄的皮肤价格相同)。为了让自己看起来高大上一些,小皮球决定给同学们展示一下自己的皮肤,展示的思路是这样的:对于有皮肤的每一个英雄,随便选一个皮肤给同学看。比如,小皮球共有 (5) 个英雄,这 (5) 个英雄分别有 (0,0,3,2,4) 款皮肤,那么,小皮球就有 (3 imes 2 imes 4=24) 种展示的策略。现在,小皮球希望自己的展示策略能够至少达到 (M) 种,请问,小皮球至少要花多少钱呢?
输入
第一行,两个整数 (N,M)
第二行,(N) 个整数,表示每个英雄的皮肤数量 (K_i)
第三行,(N) 个整数,表示每个英雄皮肤的价格 (C_i)
共 (10) 组数据,第 (t) 组数据满足:(N leq max{5,log_2^4 t},M leq 10^{17},1 leq K_i leq 10,1 leq C_i leq 199)。保证有解
输出
一个整数,表示小皮球达到目标最少的花费。
输入示例
3 24
4 4 4
2 2 2
输出示例
18
数据规模及约定
见“输入”
题解
我真是智商下线。。。这题都没想到 QAQ
dp,因为 (M) 太大,考虑将价钱作为状态。于是有 (f_{i, j}) 表示考虑前 (i) 种皮肤,花了 (j) Q币,最大的方案数是多少。因为 (K_i leq 10),暴力转移即可。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define LL long long
const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
if(Head == Tail) {
int l = fread(buffer, 1, BufferSize, stdin);
Tail = (Head = buffer) + l;
}
return *Head++;
}
LL read() {
LL x = 0, f = 1; char c = Getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
return x * f;
}
#define maxn 130
#define maxc 258710
int n, num[maxn], cost[maxn];
LL M, f[maxn][maxc];
int main() {
n = read(); M = read();
for(int i = 1; i <= n; i++) num[i] = read();
for(int i = 1; i <= n; i++) cost[i] = read();
f[0][0] = 1; int mx = 0;
for(int i = 0; i < n; i++)
for(int j = 0; j <= mx; j++) if(f[i][j]) {
f[i+1][j] = max(f[i+1][j], f[i][j]);
for(int k = 2; k <= num[i+1]; k++)
f[i+1][j+k*cost[i+1]] = max(f[i+1][j+k*cost[i+1]], min(f[i][j] * k, M)),
mx = max(mx, j + k * cost[i+1]);
}
for(int j = 0; j < maxc; j++) if(f[n][j] >= M) return printf("%d
", j), 0;
return 0;
}