analysis
首先我们看到数据范围,这个题目中的 \(m\) 给定的很小,所以我们可以考虑用状压 dp 解决这个题目。当然这个题目貌似用背包也是可以的,有神犇是拿背包做的我看见好像。
我们压缩的状态就是我们可以用来解决的题目编号。
状态表示:\(f_{i, j}\) 表示选择了前 \(i\) 个人中,解决了的问题为 \(j\) 的最小花费。
状态计算:
\[f_{i, j | s_i} \gets min(f_{i - 1, j} + x_i, f_{i, j | s_i}) \]空间复杂度 \(O(n2^m)\) 会炸,所以我们考虑优化:
由于每一次的转移只和上一层的有关,考虑滚动数组优化。
空间复杂度 \(O(2^{m + 1})\),时间复杂度 \(O(n2^m)\)。(想写 \(O(能过)\) 来着)
code time
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define rl register ll
#define foa(i, a, b) for(rl i=a; i < b; ++ i)
#define fos(i, a, b) for(rl i=a; i <= b; ++ i)
#define fop(i, a, b) for(rl i=a; i >= b; -- i)
#define ws putchar(' ')
#define wl putchar('\n')
template <class T> inline void waw(T x)
{
if(x > 9) waw(x / 10);
putchar(x % 10 ^ 48);
}
template <class T> inline void ww(T x)
{
if(x < 0) x = ~x + 1, putchar('-');
waw(x);
}
template <class T> inline void read(T &res)
{
char ch = getchar(); bool f = 0; res = 0;
for(; !isdigit(ch); ch = getchar()) f |= ch == '-';
for(; isdigit(ch); ch = getchar()) res = (res << 1) + (res << 3) + (ch ^ 48);
res = f ? ~res + 1 : res;
}
const ll N = 2100000, M = 110;
ll n, m, b, f[2][N], minn = 2e18;
struct node
{
ll x, k, q;
bool operator <(const node &x) const
{
return k < x.k;
}
} a[M];
int main()
{
read(n), read(m), read(b);
fos(i, 1, n)
{
ll cnt;
read(a[i].x), read(a[i].k), read(cnt);
while(cnt -- )
{
ll x; read(x);
a[i].q |= 1 << x - 1;
}
}
sort(a + 1, a + 1 + n);
foa(i, 1, (1 << m)) f[0][i] = 2e18;
fos(i, 1, n)
{
memcpy(f[i & 1], f[(i - 1) & 1], sizeof f[(i - 1) & 1]);
foa(j, 0, (1 << m)) f[i & 1][j | a[i].q] = min(f[i & 1][j | a[i].q], f[(i - 1) & 1][j] + a[i].x);
minn = min(minn, f[i & 1][(1 << m) - 1] + a[i].k * b);
}
if(minn == 2e18) minn = -1;
ww(minn), wl;
return 0;
}
标签:Gena,ch,putchar,res,复杂度,Cunning,void,define
From: https://www.cnblogs.com/carp-oier/p/17770796.html