Description
NOI2011 在吉林大学开始啦!为了迎接来自全国各地最优秀的信息学选手,吉林大学决定举办两场盛大的 NOI 嘉年华活动,分在两个不同的地点举办。每个嘉年华可能包含很多个活动,而每个活动只能在一个嘉年华中举办。
现在嘉年华活动的组织者小安一共收到了 n个活动的举办申请,其中第 i 个活动的起始时间为 Si,活动的持续时间为Ti。这些活动都可以安排到任意一个嘉年华的会场,也可以不安排。
小安通过广泛的调查发现,如果某个时刻,两个嘉年华会场同时有活动在进行(不包括活动的开始瞬间和结束瞬间),那么有的选手就会纠结于到底去哪个会场,从而变得不开心。所以,为了避免这样不开心的事情发生,小安要求不能有两个活动在两个会场同时进行(同一会场内的活动可以任意进行)。
另外,可以想象,如果某一个嘉年华会场的活动太少,那么这个嘉年华的吸引力就会不足,容易导致场面冷清。所以小安希望通过合理的安排,使得活动相对较少的嘉年华的活动数量最大。
此外,有一些活动非常有意义,小安希望能举办,他希望知道,如果第i 个活动必须举办(可以安排在两场嘉年华中的任何一个),活动相对较少的嘉年华的活动数量的最大值。
Solution
先把时间离散掉。
设
fi,j
f
i
,
j
表示时间
1…i
1
…
i
、一个场地选了
j
j
个活动,另一个场地最多可以选多少个活动;表示时间
i…tot
i
…
t
o
t
、
……
…
…
转移显然,第一问的答案为
max(min(j,f[tot][j]))
max
(
min
(
j
,
f
[
t
o
t
]
[
j
]
)
)
。
第二问设 dpi,j d p i , j 表示 [i,j] [ i , j ] 必选的最优值。我们枚举一个场地 1…i 1 … i 选多少个、 j…tot j … t o t 选多少个,这样是 O(n4) O ( n 4 ) 的,根据单调性,我们可以优化成 O(n3) O ( n 3 ) 。
Code
/************************************************
* Au: Hany01
* Date: Aug 4th, 2018
* Prob: BZOJ2436 NOI2011 NOI嘉年华
* Email: hany01@foxmail.com
* Inst: Yali High School
************************************************/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
#define rep(i, j) for (register int i = 0, i##_end_ = (j); i < i##_end_; ++ i)
#define For(i, j, k) for (register int i = (j), i##_end_ = (k); i <= i##_end_; ++ i)
#define Fordown(i, j, k) for (register int i = (j), i##_end_ = (k); i >= i##_end_; -- i)
#define Set(a, b) memset(a, b, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define x first
#define y second
#define pb(a) push_back(a)
#define mp(a, b) make_pair(a, b)
#define SZ(a) ((int)(a).size())
#define INF (0x3f3f3f3f)
#define INF1 (2139062143)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define y1 wozenmezhemecaia
template <typename T> inline bool chkmax(T &a, T b) { return a <= b ? a = b, 1 : 0; }
template <typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
inline int read() {
static int _, __; static char c_;
for (_ = 0, __ = 1, c_ = getchar(); c_ < '0' || c_ > '9'; c_ = getchar()) if (c_ == '-') __ = -1;
for ( ; c_ >= '0' && c_ <= '9'; c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ ^ 48);
return _ * __;
}
const int maxn = 205;
int n, tot, ls[maxn << 1], f[maxn << 1][maxn], g[maxn << 1][maxn], s[maxn], t[maxn], sum[maxn << 1][maxn << 1], Ans, dp[maxn << 1][maxn << 1];
inline int calc(int i, int j, int l, int r) {
if (f[i][l] < 0 || g[j][r] < 0) return -INF;
static int x, y; x = f[i][l] + g[j][r], y = l + r;
if (x < y) x += sum[i][j]; else y += sum[i][j];
return min(x, y);
}
int main()
{
#ifdef hany01
freopen("bzoj2436.in", "r", stdin);
freopen("bzoj2436.out", "w", stdout);
#endif
n = read();
For(i, 1, n) ls[++ tot] = s[i] = read(), ls[++ tot] = t[i] = read() + s[i];
sort(ls + 1, ls + 1 + tot);
For(i, 1, n) s[i] = lower_bound(ls + 1, ls + 1 + tot, s[i]) - ls, t[i] = lower_bound(ls + 1, ls + 1 + tot, t[i]) - ls;
For(i, 1, tot) For(j, i, tot) For(k, 1, n)
if (i <= s[k] && t[k] <= j) ++ sum[i][j];
Set(f, 128), Set(g, 128), f[0][0] = 0, g[tot + 1][0] = 0;
For(i, 1, tot) For(j, 0, n) rep(k, i) {
chkmax(f[i][j], f[k][j] + sum[k][i]);
if (j >= sum[k][i]) chkmax(f[i][j], f[k][j - sum[k][i]]);
}
For(i, 1, n) chkmax(Ans, min(i, f[tot][i]));
printf("%d\n", Ans);
Fordown(i, tot, 1) For(j, 0, n) For(k, i + 1, tot + 1) {
chkmax(g[i][j], g[k][j] + sum[i][k]);
if (j >= sum[k][i]) chkmax(g[i][j], g[k][j - sum[i][k]]);
}
For(i, 1, tot) For(j, i, tot) if (sum[i][j]) {
int r = n, now, tmp;
For(l, 0, n) {
now = calc(i, j, l, r);
while (r) if (chkmax(now, calc(i, j, l, r - 1))) -- r; else break;
chkmax(dp[i][j], now);
}
}
For(i, 1, n) {
Ans = 0;
For(l, 1, s[i]) For(r, t[i], tot)
chkmax(Ans, dp[l][r]);
printf("%d\n", Ans);
}
return 0;
}