小苯的粉丝关注
[题目链接](https://www.nowcoder.com/practice/697cf95e85cc4061b1d3429d39e00780)
思路
小苯有 个旧账号,第
个账号有
个粉丝。他要让新账号恰好获得
个粉丝。在第
个旧账号发一次推荐文章,新账号涨粉
;他还可以最多选择一个旧账号多次发推荐文章,该账号涨粉
(不取半)。求最少在几个旧账号发文。
问题转化
选择一个账号子集 ,从中至多挑一个账号
获得
的贡献,其余账号
各贡献
。要求总贡献恰好等于
,最小化
。
枚举 + 0-1 背包
由于 ,数据范围很小,可以枚举"哪个账号被选为多次发文的账号"(也可以不选),然后用 0-1 背包求剩余目标的最少物品数。
具体地,令 。枚举
(
表示不选任何账号多次发文,
表示选第
个账号):
- 计算剩余目标
。若
,跳过。
- 在
上做 0-1 背包:
表示恰好凑出和为
所需的最少物品数。
- 若
有解,则答案候选为
。
取所有候选的最小值即为答案。若无解,输出 。
样例演示
输入 ,
,对应
。
- 选
(账号 3 多次发文,贡献
),剩余目标
。
- 在
(去掉
)中凑出
,选
,用
个物品。
- 总计
个账号,即为最优解。
复杂度分析
- 时间复杂度:
。枚举
共
轮,每轮做一次
的 0-1 背包。
- 空间复杂度:
,DP 数组大小。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, k;
scanf("%d%d", &n, &k);
vector<int> a(n);
for (int i = 0; i < n; i++) scanf("%d", &a[i]);
vector<int> b(n);
for (int i = 0; i < n; i++) b[i] = a[i] / 2;
int ans = INT_MAX;
for (int j = -1; j < n; j++) {
int target = k - (j >= 0 ? a[j] : 0);
if (target < 0) continue;
vector<int> dp(target + 1, INT_MAX);
dp[0] = 0;
for (int i = 0; i < n; i++) {
if (i == j || b[i] == 0) continue;
for (int s = target; s >= b[i]; s--) {
if (dp[s - b[i]] != INT_MAX) {
dp[s] = min(dp[s], dp[s - b[i]] + 1);
}
}
}
if (dp[target] != INT_MAX) {
int cost = dp[target] + (j >= 0 ? 1 : 0);
ans = min(ans, cost);
}
}
printf("%d\n", ans == INT_MAX ? -1 : ans);
return 0;
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(), k = sc.nextInt();
int[] a = new int[n];
for (int i = 0; i < n; i++) a[i] = sc.nextInt();
int[] b = new int[n];
for (int i = 0; i < n; i++) b[i] = a[i] / 2;
int ans = Integer.MAX_VALUE;
for (int j = -1; j < n; j++) {
int target = k - (j >= 0 ? a[j] : 0);
if (target < 0) continue;
int[] dp = new int[target + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = 0;
for (int i = 0; i < n; i++) {
if (i == j || b[i] == 0) continue;
for (int s = target; s >= b[i]; s--) {
if (dp[s - b[i]] != Integer.MAX_VALUE) {
dp[s] = Math.min(dp[s], dp[s - b[i]] + 1);
}
}
}
if (dp[target] != Integer.MAX_VALUE) {
int cost = dp[target] + (j >= 0 ? 1 : 0);
ans = Math.min(ans, cost);
}
}
System.out.println(ans == Integer.MAX_VALUE ? -1 : ans);
}
}

京公网安备 11010502036488号