[BZOJ5018][Snoi2017]英雄联盟
[BZOJ5018][Snoi2017]英雄联盟
试题描述
正在上大学的小皮球热爱英雄联盟这款游戏,而且打的很菜,被网友们戏称为「小学生」。现在,小皮球终于受不了网友们的嘲讽,决定变强了,他变强的方法就是:买皮肤!小皮球只会玩 \(N\) 个英雄,因此,他也只准备给这 \(N\) 个英雄买皮肤,并且决定,以后只玩有皮肤的英雄。这 \(N\) 个英雄中,第 \(i\) 个英雄有 \(K_i\) 款皮肤,价格是每款 \(C_i\) Q币(同一个英雄的皮肤价格相同)。为了让自己看起来高大上一些,小皮球决定给同学们展示一下自己的皮肤,展示的思路是这样的:对于有皮肤的每一个英雄,随便选一个皮肤给同学看。比如,小皮球共有 \(5\) 个英雄,这 \(5\) 个英雄分别有 \(0,0,3,2,4\) 款皮肤,那么,小皮球就有 \(3 \times 2 \times 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\n", j), 0;
return 0;
}