首先一个想法就是可以考虑令 \(dp_{i, j}\) 表示当前考虑到了第 \(i\) 个商店,当前到了时刻 \(j\) 能走过最多的商店数量。但是你会发现这个 \(dp\) 转移的顺序并不是简单的从左往右转移,因为可能先走后面一个商店再走前面的一个商店,这时候我们一般的处理方法就是找到一种拓扑序使得这个 \(dp\) 能够转移。

我们会发现上面的 \(dp\) 的问题在于,可能会先走后面的商店再走前面的商店,那么我们能否对这些商店按某种方式排序后使得先走前面的商店一定比先走后面的商店更优呢?我们来试试看,对于任意两个商店 \(x, y\) 在某一时刻 \(t\) 如果先走 \(x\) 比先走 \(y\) 更优,则有:

\[((t + 1)(a_x + 1) + b_x + 1)(a_y + 1) + b_y < ((t + 1)(a_y + 1) + b_y + 1)(a_x + 1) + b_x
\]

暴力拆解之后可以得到:

\[b_x a_y - a_x b_y < a_x - a_y
\]

因此我们只需要先将这些商店按照上面这个方法排序,这样就能保证转移顺序一定是从左往右了。再回到这个 \(dp\),你会发现这个 \(dp\) 的状态涉及 \(T\) 是不行的,能不能改写这个状态呢?你会发现直接将第二维和 \(dp\) 值直接调换即可,即令 \(dp_{i, j}\) 表示考虑完前 \(i\) 个商店,当前已经过 \(j\) 个商店的最小耗时。但是时间复杂度还是不够,但可以注意到的是如果 \(a_x \ne 0\) 则 \((t + 1)(a_x + 1) + b_x > 2t\) 也就是说我们最多会选 \(\log T\) 个 \(a_x > 0\) 的商店,这样我们 \(dp\) 的状态数就可以做到 \(O(n \log T)\) 了,转移的时候直接枚举上一次走的商店即可。注意到这是一个前缀 \(\max\) 的形式,\(dp\) 时一路维护前缀 \(\max\) 即可。

那么对于 \(a_x = 0\) 的商店呢?你会发现,这些 \(a_x = 0\) 的商店 \(x\) 放在最后走一定是最优的,因为如果放在前面走必然会因为后面存在一个 \(a_y > 0\) 使得 \(x\) 对时间的贡献会翻倍;而且我们一定会选择走 \(b_x\) 最小的那几个商店,所以我们先将 \(a_x = 0\) 的这部分商店按找 \(b_x\) 从小到大排序。因此,我们在最后统计答案的时候,对于每个 \(dp_{i, j}\) 找到最后一个 \(P\) 使得 \(\sum\limits_{k = 1} ^ P b_k + 1 \le T - dp_{i, j}\),直接记录 \(b\) 数组的前缀和二分即可。

#include<bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for(int i = l; i <= r; ++i)
const int N = 200000 + 5;
const int M = 30 + 5;
const int inf = 1000000000 + 1;
struct node{
int a, b;
}a[N], b[N];
int n, m, T, cnt, ans, S[N], mx[M], dp[N][M];
int read(){
char c; int x = 0, f = 1;
c = getchar();
while(c > '9' || c < '0'){ if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
bool cmp1(node x, node y){
return 1ll * x.b * y.a - 1ll * x.a * y.b < x.a - y.a;
}
bool cmp2(node x, node y){
return x.b < y.b;
}
int main(){
cnt = read(), T = read();
rep(i, 1, cnt){
a[i].a = read(), a[i].b = read();
if(!a[i].a) b[++m] = a[i];
else a[++n] = a[i];
}
sort(a + 1, a + n + 1, cmp1), sort(b + 1, b + m + 1, cmp2);
rep(i, 0, n) rep(j, 0, M - 5) dp[i][j] = mx[j] = inf;
dp[0][0] = mx[0] = 0;
rep(i, 1, n){
rep(j, 1, M - 5) if(1ll * (mx[j - 1] + 1) * (a[i].a + 1) + a[i].b <= T){
dp[i][j] = (mx[j - 1] + 1) * (a[i].a + 1) + a[i].b;
}
rep(j, 1, M - 5) mx[j] = min(mx[j], dp[i][j]);
}
rep(i, 1, m) S[i] = min(S[i - 1] + b[i].b + 1, inf);
ans = upper_bound(S + 1, S + m + 1, T) - S - 1;
rep(i, 1, n) rep(j, 1, M - 5) if(dp[i][j] < inf){
int P = upper_bound(S + 1, S + m + 1, T - dp[i][j]) - S;
ans = max(ans, j + P - 1);
}
printf("%d", ans);
return 0;
}

AT5760 Manga Market的更多相关文章

  1. LYDSY模拟赛day2 Market

    /* orz claris,这个题的解法非常巧妙,首先是时间问题,其实这个问题只要离线处理一下就可以了,把物品和询问都按照时间排序,然后看一下能不能满足.然后,因为容量<=10^9,显然是不可能 ...

  2. Android网页中tel,sms,mailTo,Intent,Market协议用法总结

     tel:协议---拨打电话 <a href="tel:">调出拨号界面</a> <a href="tel:10086">调 ...

  3. [Xamarin] 製作Options Menu、Intent 呼叫網址和Market (转帖)

    Android的設計如果沒意外的話通常有三棵按鈕,BACK,HOME,OPTION (圖片來源:http://developer.android.com/design/index.html) 在OPT ...

  4. ZOJ 3910 Market ZOJ Monthly, October 2015 - H

    Market Time Limit: 2 Seconds      Memory Limit: 65536 KB There's a fruit market in Byteland. The sal ...

  5. 发布android app到android market的方法

      转载自: http://www.stwind.org/android-market 给你的程序签名注意事项:所有提交到Market的程序必须经过签名.未经签名的程序不能安装.你可以使用个人证书去签 ...

  6. 在android market发布个人免费应用的步骤

    写了一段时间的android应用了,只是在自己手机上面安装. 上周申请了android developer,需要一次性25美元的程序开发注册费用.费用需要用google checkout,所以还要先申 ...

  7. 【转】开发者教程:如何将Android应用发布到Google Play(Android Market)官方市场

    原文网址:http://www.chinaapp.org/game/5594.html 作为一个专业的App开发者网站,竟然没有一篇讲述如何将Android App发布到Google Play的教程, ...

  8. Android Market 分析【安卓市场】

    安卓市场: 通过对表的分析,“下载任务”的数据来源于数据库[app_download],“已安装”的数据来源于数据库[software_installed]. 数据分析:----- bash-3.2# ...

  9. android market 选择

    通过Java包名直接定位到你的App http://market.android.com/details?id=<java包名>或者market://details?id=<java ...

随机推荐

  1. 离线版centos8环境部署迁移监控操作笔记

    嗨咯,前两天总结记录了离线版centos8下docker的部署笔记,今天正好是2021年的最后一天,今天正好坐在本次出差回家的列车上,车上没有上面事做,索性不如把本次离线版centos8环境安装的其他 ...

  2. CapstoneCS5212替代IT6516方案|DP转VGA芯片|替代兼容IT6516

    台湾联阳IT6516是一种高性能的DP显示端口到VGA转换器方案芯片.IT6516结合DisplayPort接收器和三重DAC,通过转换功能支持DisplayPort输入和VGA输出.内置Displa ...

  3. Java初学者作业——计算大庆路小学的面积练习

    返回本章节 返回作业目录 需求说明: 大庆路小学因为装修需要对教室的一侧墙面进行重新粉刷,墙面安装了一面黑板,墙面的长和高以及黑板的长和高. 请编写Java程序计算出需要粉刷的墙面面积.功能要求:输入 ...

  4. MySQL高级查询与编程笔记 • 【第3章 子查询】

    全部章节   >>>> 本章目录 3.1 子查询定义和单行子查询 3.1.1 子查询定义 3.1.2 单行子查询应用 3.1.4 实践练习 3.2 多行子查询应用 3.2.1 ...

  5. Gradle sync failed (3 s 402 ms) - Android Studio问题解决方法

    问题:Gradle同步失败 解决方法: 删除gradle-wrpper.jar中的 implementation 'com.android.support:design:30.+' 最后在Build中 ...

  6. javaScript系列 [43]-TS、Class and ES5

    本文讨论Typescript中的Class同ES5构造函数的对应关系,涉及TypeScript的诸多语法.构造函数.面向对象以及原型对象等相关知识点细节,本文只简单对比并不进行深入展开. TypeSc ...

  7. 合并区间(c++)

    L. 合并区间 内存限制:256 MiB 时间限制:1000 ms 标准输入输出 题目类型:传统 评测方式:文本比较 题目描述 给出n个闭区间,把其中有重叠的区间合并为一个区间. 例如,给出4个区间, ...

  8. Django_模板中的URL参数化(四)

    去除模板中的硬编码 URL 在案例中的 test1/templates/booktest/index.html 文件里编写的链接都硬编码的链接,比如: <a href="/bookte ...

  9. vue 因为使用scope后选择器和标签出现[data-v

    使用scope的以后出现datd-v,例如: <div data-v-2311c06a class="button-warp"> <button data-v-2 ...

  10. SYCOJ223图书管理员

    题目-图书管理员 (shiyancang.cn) 图书馆中每本书都有一个图书编码,可以用于快速检索图书,这个图书编码是一个正整数. 每位借书的读者手中有一个需求码,这个需求码也是一个正整数. 如果一本 ...