状压训练
1, CF418 Cunning Gena
大意: Gena参加一个比赛, Gena有n个朋友, 比赛有m道题, Gena自己并不会做题, Gena能花费$w_i$元让第$i$个朋友帮忙做出所有他会的题, 但要求Gena有至少$k_i$个显示屏, 一台显示屏$b$元, 求Gena解决所有题的最少花费.
比较简单的状压, 按k排序一下再dp就好了, 卡空间要滚动数组
#include <iostream> #include <algorithm> #include <cstdio> #include <string.h> #define REP(i,a,n) for(int i=a;i<=n;++i) using namespace std; typedef long long ll; const int N = 110; const ll INF = 0x3f3f3f3f3f3f3f3f; int n, m, b; struct _ { int w, k, v; } a[N]; ll dp[2][1<<20]; void chkmin(ll &x, ll y) {x=min(x,y);} int main() { scanf("%d%d%d", &n, &m, &b); REP(i,1,n) { int cnt; scanf("%d%d%d", &a[i].w, &a[i].k, &cnt); REP(j,1,cnt) { int t; scanf("%d", &t); a[i].v |= 1<<t-1; } } sort(a+1,a+1+n,[](_ a,_ b){return a.k<b.k;}); memset(dp[0], 0x3f, sizeof dp[0]); dp[0][0] = 0; ll ans = INF; int mx = (1<<m)-1, cur = 0; REP(i,1,n) { cur ^= 1; memcpy(dp[cur], dp[cur^1], sizeof dp[cur]); REP(j,0,mx) if (dp[cur^1][j]!=INF) { chkmin(dp[cur][j|a[i].v],dp[cur^1][j]+a[i].w); } REP(j,0,mx) if (dp[cur][j]!=INF) { dp[cur][j] += (ll)b*(a[i].k-a[i-1].k); } ans = min(ans, dp[cur][mx]); } printf("%lld\n", ans==INF?-1:ans); }
练习2 luogu P2157 学校食堂
大意: n个同学排队去打饭, 第$i$个同学所需的菜口味$a_i$, 最多容忍排在他后面$b_i$个人先打饭, 食堂每做一道菜用时为 $a \wedge b$, a为上道菜的口味, b为当前做的菜的口味, 第一道菜不用时间, 求食堂做完所有菜的最短用时