A 老夫
题目大意 : n个人,如果能忍受广告就广告,如果能支付的起就交钱,问商家在每个播放广告数是能获得的最大利益
-
按忍受广告数量从小到大排序,那么就是前面的人去交钱或是推出,后面的人看广告
-
不看广告的人如果从大到小排序后,交钱的就是一段前缀,这样,贡献就是 \(a_ii\) 的最大值
-
以a为下标,分块维护凸包,找最大值的时候单调队列即可
Code
Show Code
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5, M = 320;
int read(int x = 0, int f = 1, char c = getchar()) {
for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
for (; c >='0' && c <='9'; c = getchar()) x = x * 10 + c - '0';
return x * f;
}
int n, k, ma, mb, a[N], b[N], p[N];
int c[N], tag[M], R[M], q[M][M], l[M], r[M];
ll w[N], ans;
bool Cmp(int x, int y) {
return b[x] < b[y];
}
ll Cal (int x) {
return w[x] + 1ll * tag[c[x]] * x;
}
bool Judge(int x, int y, int z) {
return (w[y] - w[x]) * (z - x) < (w[z] - w[x]) * (y - x);
}
void Solve(int x) {
int cx = c[x];
for (int i = 1; i < cx; ++i) {
tag[i]++;
while (l[i] < r[i] && Cal(q[i][l[i]]) < Cal(q[i][l[i]+1])) l[i]++;
ans = max(ans, Cal(q[i][l[i]]));
}
int &tp = r[cx] = 0; l[cx] = 1;
for (int i = R[cx-1] + 1; i <= R[cx]; ++i) {
w[i] += 1ll * tag[cx] * i;
if (i <= x) w[i] += i;
ans = max(ans, w[i]);
while (tp && w[i] >= w[q[cx][tp]]) tp--;
while (tp > 1 && Judge(q[cx][tp-1], q[cx][tp], i)) tp--;
q[cx][++tp] = i;
}
tag[cx] = 0;
}
int main() {
freopen("laofu.in", "r", stdin);
freopen("laofu.out", "w", stdout);
n = read(), k = read();
for (int i = 1; i <= n; ++i) {
a[i] = read(); b[i] = read(); p[i] = i;
ma = max(ma, a[i]), mb = max(mb, b[i]);
}
int sq = sqrt(ma);
for (int i = 1; i <= ma; ++i) {
c[i] = (i - 1) / sq + 1;
R[c[i]] = i; l[c[i]] = 1;
q[c[i]][++r[c[i]]] = i;
}
sort(p + 1, p + n + 1, Cmp);
for (int i = 1, j = 1; i <= mb + 1; ++i) {
for (; j <= n && b[p[j]] < i; ++j) Solve(a[p[j]]);
printf("%lld ", ans + 1ll * k * i * (n - j + 1));
}
return 0;
}
B 打算 (Unaccepted)
题目大意 :
Code
Show Code
C (Unaccepted)
题目大意 :
Code
Show Code