http://acm.hdu.edu.cn/showproblem.php?pid=4381
1 ai xi :You can choose any xi black boxes in interval [1,ai], and color them white;
2 ai xi :You can choose any xi black boxes in interval [ai,n], and color them white;
就是给你m个这两种操作,每个操作你可以选做或者不做,还可以选择操作的先后顺序,问最多可以有多少格变成白色
对两种操作分开来看
以第一种操作为例,仔细观察一下,可以得出一个贪心的结论,对操作按ai从小到大排个序之后,对于每一个操作,假如我要使用它,那应该尽可能的先对最左边的可color的格子变色白色,这样保证不会更差。这样的话就可以利用一个类似背包的DP计算出将左边1...j个全部变成白色有需要的最少操作数
对于第二种操作也是同理,最后将两个DP值合并一下就是了。
#define pb push_back #define mp make_pair #define fi first #define se second #define all(a) (a).begin(),(a).end() #define FOR(i,a,b) for (int i=(a);i<(b);i++) #define FORD(i,a,b) for (int i=(a); i>=(b); i--) #define REP(i,b) FOR(i,0,b) #define sf scanf #define pf printf #define Maxn 1010 using namespace std; const int maxint = -1u>>1; const int inf = 1<<29; const double pi = 3.14159265358979323; const double eps = 1e-8; typedef pair<int,int> pii; typedef vector<int> vi; typedef vector<int>::iterator vit; int n, m; pii op1[Maxn], op2[Maxn]; int n1, n2; int dpl[Maxn], dpr[Maxn]; bool cmp2(pii a, pii b) { return a.fi > b.fi || (a.fi == b.fi && a.se < b.se); } void init_dp() { REP(j, n+2) dpl[j] = dpr[j] = inf; sort(op1+1, op1+n1+1); dpl[0] = 0; FOR(i, 1, n1+1) { FORD(j, op1[i].fi, op1[i].se) dpl[j] = min(dpl[j], dpl[j-op1[i].se] + 1); } sort(op2+1, op2+n2+1, cmp2); dpr[n+1] = 0; FOR(i, 1, n2+1) { FOR(j, op2[i].fi, n-op2[i].se+2) dpr[j] = min(dpr[j], dpr[j+op2[i].se] + 1); } } int main() { int T, ca = 0, type, a, b; sf("%d", &T); while (T--) { sf("%d%d", &n, &m); n1 = n2 = 0; REP(i, m) { sf("%d%d%d", &type, &a, &b); if (type == 1) op1[++n1] = mp(a, b); else op2[++n2] = mp(a, b); } init_dp(); int ans1 = 0, ans2 = inf; REP(i, n+1) FOR(j, i+1, n+2) { if (dpl[i] != inf && dpr[j] != inf) { if (i + n + 1 - j > ans1) ans1 = i + n + 1 - j, ans2 = dpl[i] + dpr[j]; else if (i + n + 1 - j == ans1) ans2 = min(ans2, dpl[i] + dpr[j]); } } if (ans2 == inf) ans2 = 0; pf("Case %d: %d %d\n", ++ca, ans1, ans2); } return 0; }