题面
题解
现场得分:100/100
我竟然现场写对斜率优化了!
- 我们发现一定是始终在用v最大的工厂。我们的每一步的新工厂一定是c和v都比前一个大的。
- 于是我们可以按照v先排个序,再处理一下,把所有存在其他工厂比自己v大,c小的那些废物工厂扔掉。
- 我们还能发现,买下第(i)个工厂之后,我以后的时刻的金币数一定是一个斜率为(v_i)的直线。
- 我们就有了一个(O(n^2))的dp,记(f_i)表示买下了第(i)的工厂,得到的直线截距最大是多少。
- 转移显然。
- 我这里都说是直线了,显然可以斜率优化。
代码
#include<bits/stdc++.h>
#define LL long long
#define MAXN 200100
#define INF 10000000000000000
using namespace std;
template<typename T>void Read(T &cn)
{
char c; int sig = 1;
while(!isdigit(c = getchar())) if(c == '-') sig = -1; cn = c-48;
while(isdigit(c = getchar())) cn = cn*10+c-48; cn*=sig;
}
template<typename T>void Write(T cn)
{
if(cn < 0) {putchar('-'); cn = 0-cn; }
int wei = 0; T cm = 0; int cx = cn%10; cn/=10;
while(cn) wei++, cm = cm*10+cn%10, cn/=10;
while(wei--) putchar(cm%10+48), cm /= 10;
putchar(cx+48);
}
template<typename T>void Max(T &cn, T cm) {cn = cn < cm ? cm : cn; }
template<typename T>void Min(T &cn, T cm) {cn = cn < cm ? cn : cm; }
struct qwe{
LL v,c;
void getit() {Read(v); Read(c); }
inline friend bool operator <(qwe a, qwe b) {return a.v == b.v ? a.c > b.c : a.v < b.v; }
};
struct xian{
LL k, b;
LL suan(LL cn) {return (cn - b+k-1)/k; }
void mk(LL cn, LL cm) {k = cn; b = cm; }
};
qwe a[MAXN+1];
int n;
LL m;
int xu[MAXN+1], xlen;
LL f[MAXN+1], g[MAXN+1];
xian zhan[MAXN+1];
int l, r;
int jiao_z(LL cn, xian A, xian B) {return cn*(A.k - B.k) <= (B.b - A.b); }
int jiao(xian A, xian B, xian C)
{
double db1 = (B.b-A.b), db2 = (C.b-B.b);
double dk1 = (A.k-B.k), dk2 = (B.k-C.k);
return db1*dk2 >= db2*dk1;
}
LL qiu(int cn, int cm)
{
while(l < r && jiao_z(zhan[l].suan(cn), zhan[l], zhan[l+1])) l++;
if(l > r) return -INF;
return -zhan[l].suan(cn)*(cm-zhan[l].k) - cn + zhan[l].b;
}
void zeng(int ck, LL cb)
{
xian lin; lin.mk(ck, cb);
while(l < r && jiao(zhan[r-1], zhan[r], lin)) r--;
zhan[++r] = lin;
}
int main()
{
// freopen("collect.in","r",stdin);
// freopen("collect.out","w",stdout);
Read(n); Read(m);
for(int i = 1;i<=n;i++) a[i].getit();
sort(a+1, a+n+1); xlen = 0;
for(int i = 1;i<=n;i++)
{
if(a[i].v <= 0) continue;
while(xlen && a[xu[xlen]].c > a[i].c) xlen--;
xu[++xlen] = i;
}
for(int i = 1;i<=xlen;i++) a[i] = a[xu[i]];
n = xlen;
f[0] = 0; a[0].v = a[0].c = 0;
l = 1; r = 0; f[1] = 0;
zeng(a[1].v, f[1]);
LL ans = (m + a[1].v-1)/a[1].v;
for(int i = 2;i<=n;i++)
{
f[i] = qiu(a[i].c, a[i].v);
zeng(a[i].v, f[i]);
Min(ans, (m - f[i] + a[i].v-1)/a[i].v);
}
Write(ans); puts("");
return 0;
}