P2877 [USACO07JAN]牛校Cow School
$01$规划
$01$规划优质讲解:传送门
考虑先将每一科按 $t/p$ 从小到大排序,枚举每一个 $D$(删除的考试数量)
显然一开始的成绩是 $\frac{\sum_{i=d+1}^nt[i]}{\sum_{i=d+1}^{n}p[i]}$,设它为 $st[D]/sp[D]$
然后根据$01$规划的套路考虑把所有的成绩 $t[i]$ 减去 $st[D]/sp[D]*p[i]$
这样做了以后,如果可以使成绩更优,那么说明区间 $[d+1,n]$ 的 $t[i]$ 的最小值小于区间 $[1,d]$ 的 $t[i]$ 的最大值
(就是说我们本来可以选一个区间 $[1,d]$ 的更优的数,但是被删掉了)
然后就有一个 $n^2$ 的算法,枚举 $D$,然后把 $t$ 按套路操作,然后求 $[1,d]$ 区间最大值,$[d+1,n]$ 区间最小值,比较一下就好了
接下来,发现有很多东西是冗余的,没有必要每次都重新算,考虑 $D$ 的变化产生的影响
想想前面枚举完一个 $D$ 了以后要干嘛,求区间 $[d+1,n]$ 的 $t[i]-st[D]/sp[D]*p[i]$ 的最小值,
求区间 $[1,d]$ 的 $t[i]-st[D]/sp[D]*p[i]$ 的最大值。
设 $f[i]$ 表示区间 $[1,i]$,$t$ 变换后的最大值,那么显然 $f[i]=max(t[j]-st[i]/sp[i]*p[j])\ ,\ j \in [1,i]$,
发现好像可以斜率优化?
$st[i]/sp[i]*p[j]+f[i]=t[j]$,那么 $k=st[i]/sp[i],x=p[j],b=f[i],y=t[j] $,原式就变成了 $kx+b=y$ 的形式,可以斜率优化!
同样的设 $g[i]$ 表示区间 $[i+1,n]$,$t$ 变换后的最小值,那么 $g[i]=min(t[j]-st[i]/sp[i]*p[j]),\ j \in [i+1,n]$,同样可以斜率优化
可以发现,随着 $i$ 的增加 $k=st[i]/sp[i]$ 是不降的,但是显然 $x$ 是不单调的
所以我无脑强行上了两遍 $CDQ$ 求 $f$ 和 $g$,貌似有 $O(n)$ 用 $Graham$ 维护凸包的更优解法?
最后枚举 $D$ ,比较一下 $f[d]$ 和 $g[d]$ 的大小关系就好啦
具体可以看代码来理解
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
using namespace std;
typedef long long ll;
typedef double db;
inline int read()
{
int x=,f=; char ch=getchar();
while(ch<''||ch>'') { if(ch=='-') f=-; ch=getchar(); }
while(ch>=''&&ch<='') { x=(x<<)+(x<<)+(ch^); ch=getchar(); }
return x*f;
}
const int N=2e5+;
const ll INF=1e18;
int n,st[N],sp[N];
db f[N],g[N];
struct nod {//存每一科的数据
int p,t;//分母,分子
inline bool operator < (const nod &tmp) const {//按分子除分母排序
return t*tmp.p<tmp.t*p;//避免除法,用等价的乘法是好习惯
}
}d[N];
struct Poi {//斜率优化的点 (或向量)
int x,y;
Poi (int x=,int y=) : x(x) , y(y) {}
inline Poi operator - (const Poi &tmp) const {//点减点就是向量,用向量维护凸包可以避免精度问题,速度也快
return Poi(x-tmp.x,y-tmp.y);
}
}T[N],tmp[N];
int Q[N];//存当前凸包
inline ll Cross(Poi A,Poi B) { return 1ll*A.x*B.y-1ll*B.x*A.y; }//向量叉积维护凸包
inline db calc(int i,int j) { return 1.0*T[j].y-1.0*st[i]/sp[i]*T[j].x; }//计算dp值
inline void merge(int l,int r,int mid)//按x归并排序
{
int pl=l,pr=mid+;
for(int p=l;p<=r;p++)
{
if( pl<=mid && (pr>r||T[pl].x<T[pr].x) ) tmp[p]=T[pl++];
else tmp[p]=T[pr++];
}
for(int p=l;p<=r;p++) T[p]=tmp[p];
}
void CDQ_f(int l,int r)//CDQ求f,求i属于[l,r]的f[i]值
{
if(l==r) { f[l]=max(f[l],calc(l,l)); return; }//当前区间只有一个点了,用自己更新自己
int mid=l+r>>,L=,R=;
CDQ_f(l,mid);//先处理左边[l,mid]的所有f
//此时左边所有点已经按x排好序了
for(int i=l;i<=mid;i++)//维护左边所有点的凸包
{
while( L<R && Cross(T[i]-T[Q[R-]],T[Q[R]]-T[Q[R-]])<= ) R--;
Q[++R]=i;
}
for(int i=mid+;i<=r;i++)//斜率有序,直接用刚刚维护好的凸包更新[mid+1,r]的f
{
while( L<R && calc(i,Q[R-])>=calc(i,Q[R]) ) R--;
int j=Q[R]; f[i]=max(f[i],calc(i,j));
}
CDQ_f(mid+,r); merge(l,r,mid);//处理完记得按x排序
}
void CDQ_g(int l,int r)//处理g同理
{
if(l==r) return;//注意g[i]的区间不包含i (i<j<=n)
int mid=l+r>>,L=,R=;
CDQ_g(mid+,r);//注意现在是先处理右边的g了
for(int i=mid+;i<=r;i++)//维护右边的凸包
{
while( L<R && Cross(T[i]-T[Q[R-]],T[Q[R]]-T[Q[R-]])>= ) R--;
Q[++R]=i;
}
for(int i=l;i<=mid;i++)//更新左边
{
while( L<R && calc(i,Q[L])>=calc(i,Q[L+]) ) L++;
int j=Q[L]; g[i]=min(g[i],calc(i,j));
}
CDQ_g(l,mid); merge(l,r,mid);//同样记得merge
}
vector <int> ans;//维护答案
int main()
{
n=read();
for(int i=;i<=n;i++) d[i].t=read(),d[i].p=read();
sort(d+,d+n+);//先按t/p排序
for(int i=n-;i;i--) { st[i]=st[i+]+d[i+].t; sp[i]=sp[i+]+d[i+].p; }//求出st,sp
for(int i=;i<=n;i++)
{
T[i]=Poi(d[i].p,d[i].t);//初始化点
f[i]=-INF; g[i]=INF;//注意初始值
}
//斜率有序
CDQ_f(,n);
for(int i=;i<=n;i++) T[i]=Poi(d[i].p,d[i].t);//记得还原回初始值
CDQ_g(,n);
for(int i=;i<=n;i++)//枚举d,更新ans
if(f[i]>g[i]) ans.push_back(i);
int len=ans.size();
printf("%d\n",len);
for(int i=;i<len;i++) printf("%d\n",ans[i]);
return ;
} /*
f[i]=T[j]-st[i]/sp[i]*P[j] j<=i
st[i]/sp[i]*P[j]+f[i]=T[j] j<=i
k=st[i]/sp[i],x=P[j],b=f[i],y=T[j]
max,维护上凸包
g[i]=T[j]-st[i]/sp[i]*P[j] j>i
st[i]/sp[i]*P[j]+g[i]=T[j] j>i
min,维护下凸包
*/
P2877 [USACO07JAN]牛校Cow School的更多相关文章
- P2877 [USACO07JAN]牛校Cow School(01分数规划+决策单调性分治)
P2877 [USACO07JAN]牛校Cow School 01分数规划是啥(转) 决策单调性分治,可以解决(不限于)一些你知道要用斜率优化却不会写的问题 怎么证明?可以暴力打表 我们用$ask(l ...
- bzoj1638 / P2883 [USACO07MAR]牛交通Cow Traffic
P2883 [USACO07MAR]牛交通Cow Traffic 对于每一条边$(u,v)$ 设入度为0的点到$u$有$f[u]$种走法 点$n$到$v$(通过反向边)有$f2[v]$种走法 显然经过 ...
- P3014 [USACO11FEB]牛线Cow Line && 康托展开
康托展开 康托展开为全排列到一个自然数的映射, 空间压缩效率很高. 简单来说, 康托展开就是一个全排列在所有此序列全排列字典序中的第 \(k\) 大, 这个 \(k\) 即是次全排列的康托展开. 康托 ...
- bzoj1612 / P2419 [USACO08JAN]牛大赛Cow Contest(Floyd)
P2419 [USACO08JAN]牛大赛Cow Contest Floyd不仅可以算最短路,还可以处理点之间的关系. 跑一遍Floyd,处理出每个点之间是否有直接或间接的关系. 如果某个点和其他$n ...
- 【洛谷】2990:[USACO10OPEN]牛跳房子Cow Hopscotch【单调队列优化DP】
P2990 [USACO10OPEN]牛跳房子Cow Hopscotch 题目描述 The cows have reverted to their childhood and are playing ...
- 洛谷——P2952 [USACO09OPEN]牛线Cow Line
P2952 [USACO09OPEN]牛线Cow Line 题目描述 Farmer John's N cows (conveniently numbered 1..N) are forming a l ...
- P2419 [USACO08JAN]牛大赛Cow Contest
P2419 [USACO08JAN]牛大赛Cow Contest 题目背景 [Usaco2008 Jan] 题目描述 N (1 ≤ N ≤ 100) cows, conveniently number ...
- 拓扑排序/DP【洛谷P2883】 [USACO07MAR]牛交通Cow Traffic
P2883 [USACO07MAR]牛交通Cow Traffic 随着牛的数量增加,农场的道路的拥挤现象十分严重,特别是在每天晚上的挤奶时间.为了解决这个问题,FJ决定研究这个问题,以能找到导致拥堵现 ...
- 洛谷P3045 [USACO12FEB]牛券Cow Coupons
P3045 [USACO12FEB]牛券Cow Coupons 71通过 248提交 题目提供者洛谷OnlineJudge 标签USACO2012云端 难度提高+/省选- 时空限制1s / 128MB ...
随机推荐
- EZOJ #226
传送门 分析 我们可以建一个k层图,把dp转移的三维对应到每个点上,每个第k层点连向0层点 我们让第0层点为实点其余为虚点,只要碰到虚点就dfs到他连得所有实点再将实点入队即可 代码 #include ...
- Python将阿拉伯数字转化为中文大写-乾颐堂
利用Python将阿拉伯数字转化为中文大写,其实最麻烦的地方就是中间空多个0的问题,这种情况下,采用拆分法则,将一个大数字,先拆分成整数部分和小数部分,再对整数部分按照仟.万.亿.兆分位拆分为四个字符 ...
- html 图片拖动不出来的脚本
function imgdragstart() { return false; } $(function(){ for (i in document.images) document.images[i ...
- HUST软工1505班第0周作业成绩公布
说明 本次公布的成绩包含三次作业的结果: 毕博平台课前测试题 第0周作业1:开设博客 第0周作业2:博客阅读和思考 如果同学对作业结果存在异议,可以: 在线平台的第一周在线答疑中创建话题申诉. 或直接 ...
- C++中的深拷贝和浅拷贝 QT中的深拷贝,浅拷贝和隐式共享
下面是C++中定义的深,浅拷贝 当用一个已初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用.也就是说,当类的对象需要拷贝时,拷贝构造函数将会被调用.以下情况都会 ...
- java String,StringBuffer,StringBuilder区别及联系
String 字符串常量(不可变)StringBuffer 字符串变量(线程安全,可变) StringBuilder 字符串变量(非线程安全,性能优,可变) 简要的说, String 类型和 Stri ...
- 字节序(Endian),大端(Big-Endian),小端(Little-Endian)
http://www.cppblog.com/tx7do/archive/2009/01/06/71276.html 在各种计算机体系结构中,对于字节.字等的存储机制有所不同,因而引发了计算机通信领域 ...
- Alpha冲刺 - (8/10)
队名:彳艮彳亍团队 组长博客:戳我进入 作业博客:班级博客本次作业的链接 Part.2 成员汇报 组员1(组长)柯奇豪 过去两天完成了哪些任务 进一步优化代码,结合自己负责的部分修改功能 代码规范完整 ...
- 个人写spark小测试
写脚本生成类似文件 java 代码 封装类 package day0327; import java.util.UUID; public class data { private String ip; ...
- 《FilthyRichClients》读书笔记(一)-SwingのEDT
<FilthyRichClients>读完了前几个章节,现将我的体会结合工作以来从事Swing桌面开发的经验,对本书的一些重要概念进行一次 分析,对书中的一些遗漏与模糊的地方及时补充,同时 ...