牛客OI周赛15-普及组
比赛链接
牛客OI周赛15-普及组
B.三角形
题目描述
上天眷顾了牛牛,给牛牛 \(\mathrm{n}\) 个宝盒。牛牛会从这 \(\mathrm{n}\) 个箱子中各取一件宝物去当掉来换钱(每个箱子中有 \(m_{i}\) 件宝物) 。 牛牛想知道他用不同的方法取宝物能当来的钱数量的前k小值,为了避免输出量过大只要输出 \(\sum a_{i}(i \leq k)\) 即可,其 中的 \(a_{i}\) 为第i/值。
输入描述:
第一行一个整数 \(n, k\), 表示宝箱个数以及前 \(\mathrm{k}\) 小的可获得的价值
接下来n行每行开头一个整数 \(m_{i}\) 表示第一个宝箱中宝物个数, 接下来 \(m_{i}\) 个数表示每件宝物的价值 \(w_{i}\)
输出描述:
一行一个整数 \(a n s\), 表示 \(\sum a_{i}(i \leq k)\)
输入
3 10
4 1 3 4 5
3 1 7 9
4 1 2 3 5
输出
57
备注:
对于 \(50 \%\) 的数据: \(n, m_{i} \leq 10\)
对于 \(100 \%\) 的数据: \(n, m_{i} \leq 100, k \leq 10000\), 保证每个宝物的价值为不超过 \(100\) 的正整数, 所有 \(m_{i}\) 的积大 于等于 \(k\)
解题思路
分组背包
-
状态表示:\(f[i][j]\) 表示前 \(i\) 个物品,价值和为 \(j\) 的方案数
-
状态计算:\(f[i][j]+=f[i-1][j-a[i][k]]\)
然后按价值从小到大选出 \(k\) 个方案来即可
- 时间复杂度:\(O(10000n\sum m)\)
代码
// Problem: 三角形
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/32343/B
// Memory Limit: 1048576 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=105;
int n,k,f[N][10005],a[N],s;
int main()
{
cin>>n>>k;
f[0][0]=1;
for(int i=1;i<=n;i++)
{
cin>>s;
for(int k=1;k<=s;k++)cin>>a[k];
for(int k=1;k<=10000;k++)
for(int j=1;j<=s;j++)
if(a[j]<=k)f[i][k]+=f[i-1][k-a[j]];
}
int res=0;
for(int i=1;i<=10000;i++)
if(f[n][i]&&k>0)
{
res+=i*min(k,f[n][i]);
k-=f[n][i];
}
cout<<res;
return 0;
}