题目 | 维克多词典
第九届中国大学生程序设计竞赛(秦皇岛)-(CCPC2023-Qinhuangdao)
J - 维克多词典
https://cpc.csgrandeur.cn/csgoj/problemset/problem?pid=1233
1 second / 256 megabytes
standard input / standard output
题目
Keyi 是一个热爱读书的中学生,并养成了每天早上阅读的习惯。
随着高考的临近,Keyi 计划每天从《维克多词典》中学习几个单词。
然而,她记忆单词的方法有点奇特。如果她今天学习了一个长度为
但是,Keyi 每天的精力是有限的,她一天最多只能学习
Keyi 不确定要如何有效地安排学习计划,以便尽量用最少的天数完成《维克多词典》的记忆。因此,她恳请您的帮助。
输入
第一行包含两个整数
第二行包含
保证对于相同长度的单词,它们不会出现超过
输出
输出一行表示 Keyi 记住整本《维克多词典》所需的最少天数。
样例
输入
5 4
1 2 1 2 1
输出
2
题解
词长度范围仅
对于一个状态
例如对于
遍历一个状态的非空子集的方式可以写作:for (int j = i; j; j = (j - 1) & i)
但是,如果一次学习的量超过
代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
constexpr int MAXN = 13;
int cnt[MAXN];
int n, w;
int sum[1 << MAXN], dp[1 << MAXN];
void solve()
{
memset(dp, 0x3f, sizeof(dp));
dp[0] = 0;
cin >> n >> w;
for (int i = 0; i < n; i++)
{
int t;
cin >> t;
cnt[t - 1]++;
}
for (int i = 0; i < (1 << MAXN); i++)
for (int j = 0; j < MAXN; j++)
if (i >> j & 1)
sum[i] += cnt[j];
for (int i = 0; i < (1 << MAXN); i++)
for (int j = i; j; j = (j - 1) & i)
if (sum[j] <= w)
dp[i] = min(dp[i], dp[i ^ j] + 1);
cout << dp[(1 << MAXN) - 1] << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
solve();
return 0;
}
本文采用 CC BY-SA 4.0 许可,本文 Markdown 源码:Haotian-BiJi