Codeforces 609D 被二分教做人
传送门:http://codeforces.com/problemset/problem/609/D
(如需转载,请注明出处,谢谢O(∩_∩)O)
题意:
Nura想买k个小玩意,她手上有 s 个burles(一种货币),有m个小玩意供她选择购买,但每个小玩意只能用dollars或者pounds来购买,所以每次购买的时候Nura都要通过汇率将她手上的burles换成dollars或者pounds,而每一天的汇率又不一样,给出n天,并且这n天中burles换成dollars和pounds的比率,问是否能在这n天中用手上的burles买下k个小玩意,如果不能,输出-1;如果能,输出最小的天数(即能使得Nura买下k个小玩意的最少天数),并在接下来的m行中,依次输出两个数字,分别是买下的小玩意的编号(按给出的顺序编号)以及买下该小玩意的日期(即第几天)。——在同一天中可以买任意多个小玩意。
解题思路与分析:
注意到数据范围是2e5,而显然需要通过某种方式来比较“天数”,直接枚举肯定很虚,所以要用到二分。
(这里给出同学写的二分的正确姿势:
int L,R,M;
while(R-L>1){
M=((R-L)>>1)+L;
if() R=M;
else L=M;
}
)
确定了用二分来枚举天数之后,就需要确定二分里面的内容。因为一天可以买多个,所以显然应该找兑换率最高的一天,即区间最小值,这里用了ST算法,O(nlogn)预处理,O(1)查询——获得了区间里burles兑换dollars和pounds最“划算”的一天后,就是确定买下k个小玩意的最小花费了,这里没有想到更简便的方法,只能用了O(mlogm)的预处理(排序),每次O(k)获取花费。用结构体存储小玩意的type,cost以及num(编号,后面输出用到),然后排序——重载小于号,先按type排,再按cost排,记录type==2的第一个小玩意对应的下标ter,之后只需要每次计算的时候比较一下,就能保证获取最小花费了(细节见代码)——获取最小花费后,将之与s比较一下即可知该区间是否可行。
代码实现过程与反思:
感觉基本上坑被踩了个尽。。
1、计算最小花费的时候,会造成int溢出,要用long long。
2、不是坑的坑:原题output部分中的”number of gadget”,是指小玩意的编号,不是数目(gadget没有s),醉。
4、细节:计算最小花费的时候,while循环应为j<m而不为j<n(j为ter为起点的下标,i从0开始),又wa一发。。
3、二分的时候,因为while中的是R-L>1,所以当n为1时,将直接跳过二分判断。并且,如果存在可行的答案,其必然为二分循环结束后的L或者R,先判L,如果L不行就判断R;如果都不行,说明不存在正确结果。这里又wa了几发,,被二分教做人。
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=2e5+,M=;
struct gadget{
int type,cost,num;
bool operator < (const gadget g) const{
return type==g.type?cost<g.cost:type<g.type;
}
}G[N];
int n,m,k,s,ter,a[N],b[N],da[N][M],db[N][M];
void init(){
for(int i=;i<n;i++) da[i][]=a[i],db[i][]=b[i];
for(int j=;(<<j)<=n;j++)
for(int i=;i+(<<j)-<n;i++){
da[i][j]=min(da[i][j-],da[i+(<<(j-))][j-]);
db[i][j]=min(db[i][j-],db[i+(<<(j-))][j-]);
}
}
int RMQ(int L,int R,int d[N][M]){
int k=;
while((<<(k+))<=R-L+) k++;
return min(d[L][k],d[R-(<<k)+][k]);
}
bool check(ll p1,ll p2){
int cnt=;
ll tot=;
int i=,j=ter;
while(j<m){
if(i==ter||cnt==k) break;
if(G[i].cost*p1<=G[j].cost*p2)
tot+=G[i++].cost*p1;
else tot+=G[j++].cost*p2;
cnt++;
}
if(cnt<k){
if(i<ter) swap(i,j),swap(p1,p2);
while(cnt<k) tot+=p2*G[j++].cost,cnt++;
}
return tot<=s;
}
int main(){
//freopen("in.txt","r",stdin);
while(~scanf("%d%d%d%d",&n,&m,&k,&s)){
for(int i=;i<n;i++)
scanf("%d",a+i);
for(int i=;i<n;i++)
scanf("%d",b+i);
ter=;
for(int i=;i<m;i++){
scanf("%d%d",&G[i].type,&G[i].cost);
if(G[i].type==) ter++;
G[i].num=i+;
}
init();
sort(G,G+m);
bool flag=false;
int L=,R=n-,mid;
ll p1,p2;
while(R-L>){
mid=((R-L)>>)+L;
p1=RMQ(,mid,da),p2=RMQ(,mid,db);
if(check(p1,p2)) R=mid;
else L=mid;
}
p1=RMQ(,L,da),p2=RMQ(,L,db);
if(check(p1,p2)) flag=true;
else{
p1=RMQ(,R,da),p2=RMQ(,R,db);
if(check(p1,p2)) flag=true;
}
if(flag){
int d1,d2;
for(int i=;i<n;i++) if(a[i]==p1){
d1=i+;break;
}
for(int i=;i<n;i++) if(b[i]==p2){
d2=i+;break;
}
printf("%d\n",max(d1,d2));
int cnt=,tot=;
int i=,j=ter;
while(j<m){
if(i==ter||cnt==k) break;
if(G[i].cost*p1<=G[j].cost*p2){
cnt++;
printf("%d %d\n",G[i++].num,d1);
}
else{
cnt++;
printf("%d %d\n",G[j++].num,d2);
}
}
if(cnt<k){
if(i<ter) swap(d1,d2),swap(i,j);
while(cnt<k) printf("%d %d\n",G[j++].num,d2),cnt++;
}
}
else puts("-1");
}
return ;
}
Codeforces 609D 被二分教做人的更多相关文章
- Codeforces #590 D 二维树状数组
题意 给一个10^5之内的字符串(小写字母)时限2s 输入n,有n个操作 (n<10^5) 当操作是1的时候,输入位置x和改变的字母 当操作是2的时候,输入区间l和r,有多少不同的字母 思路 ...
- C - Monitor CodeForces - 846D (二维前缀和 + 二分)
Recently Luba bought a monitor. Monitor is a rectangular matrix of size n × m. But then she started ...
- CodeForces 609D Gadgets for dollars and pounds
二分天数+验证 #include<cstdio> #include<cstring> #include<cmath> #include<algorithm&g ...
- Gadgets for dollars and pounds CodeForces - 609D
Nura wants to buy k gadgets. She has only sburles for that. She can buy each gadget for dollars or f ...
- Candies CodeForces - 991C(二分水题)
就是二分暴力就好了 为什么要记下来 呵呵....emm你说为什么... 行吧 好吧 我一直以为我的二分出问题了 原来不是 依旧很帅 统计的时候求的减了多少次 然后用次数乘了mid 这样做会使那个人获 ...
- Codeforces 719E (线段树教做人系列) 线段树维护矩阵
题面简洁明了,一看就懂 做了这个题之后,才知道怎么用线段树维护递推式.递推式的递推过程可以看作两个矩阵相乘,假设矩阵A是初始值矩阵,矩阵B是变换矩阵,求第n项相当于把矩阵B乘了n - 1次. 那么我们 ...
- codeforces 609D D. Gadgets for dollars and pounds(二分+贪心)
题目链接: D. Gadgets for dollars and pounds time limit per test 2 seconds memory limit per test 256 mega ...
- Codeforces 1165F2(二分内的check)
要点 二分答案,内部喜闻乐见的拖延策略:对于某个打折玩具,就选最晚的打折时间买,答案并不会变劣,只是购买时间的平移. 注意最晚时间不是预处理的东西,是二分内部的.在mid以内的最晚时间. #inclu ...
- Codeforces Round #353 (Div. 2) D. Tree Construction 二叉搜索树
题目链接: http://codeforces.com/contest/675/problem/D 题意: 给你一系列点,叫你构造二叉搜索树,并且按输入顺序输出除根节点以外的所有节点的父亲. 题解: ...
随机推荐
- 【第四课】kaggle案例分析四
Evernote Export 比赛题目介绍 facebook想要准确的知道用户登录的地点,从而可以为用户提供更准确的服务 为了比赛,facebook创建了一个虚拟世界地图,地图面积为100km2,其 ...
- IDEA 基本配置
idea使用基本配置 1配置JDK开发环境 File->project structure: 2取消自动更新 file->setting:Appearance &Behavior下 ...
- codevs 1160 蛇形矩阵
1160 蛇形矩阵 传送门 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 白银 Silver 题解 题目描述 Description 小明玩一个数字游戏,取个n行 ...
- Vector 和 Array 区别
1:array 定义的时候必须定义数组的元素个数;而vector 不需要:且只能包含整型字面值常量,枚举常量或者用常量表达式初始化的整型const对象, 非const变量以及需要到运行阶段才知道其值的 ...
- MySQL-----一对多
一对多: 用户表和部门表 用户: 用户id 用户名 部门 1 George 1 2 Elizabeth 1 3 Bruce 2 4 Catherine 3 部门: 部门id 部门名称 1 CEO ...
- TensorFlow 学习笔记(2)----placeholder的使用
此系列将会每日持续更新,欢迎关注 在TensorFlow中输入值的方式是通过placeholder来实现 例如:做两个数的乘法时,是先准备好两个place, 再将输出值定义成两数的乘法 最后利用ses ...
- STM32的USART发送数据时如何使用TXE和TC标志
在USART的发送端有2个寄存器,一个是程序可以看到的USART_DR寄存器,另一个是程序看不到的移位寄存器,对应USART数据发送有两个标志,一个是TXE=发送数据寄存器空,另一个是TC=发送结束. ...
- 【Codeforces 1114A】Got Any Grapes?
[链接] 我是链接,点我呀:) [题意] 水题 [题解] 哪个比较挑剔优先给他选>_< [代码] import java.io.*; import java.util.*; public ...
- Spring+SpringMVC+MyBatis整合教程
1.基本概念 1.1.Spring Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One ...
- 暑假集训D15总结
考试 日常爆炸= = T1数据背锅,回天乏力 推了两个小时的T2竟然莫名RE,我也是服了 T3考试时就没读懂题,做个鬼啊 今天一直在写某奇怪的技术贴,竟然没有写题解(手动滑稽) 希望明天不要乱炸吧 博 ...