Educational Codeforces Round 95 (Rated for Div. 2) A-D
A. Buying Torches
题意:
首先规定一个木棍和一个木炭可以组合成一个火把,再给出两种操作,操作一是可以用一根木棍去换根木棍,操作二是可以用根木棍去换一个木炭,初始时有一根木棍,问最少进行多少次操作可以得到个火把(组成火把的过程不花费操作次数,换句话说,只要有至少个木棍和个木炭即可达成目标)。
思路:
因为两个操作都是需要用木棍来衡量的,所以我们不妨将目标的个火把都转换为木棍,首先个火把需要个木棍和个木炭组成,而一个木炭需要个木棍,所以总共需要个木棍,而每次操作一用一根木棍去得到个木棍,实质上是增加个木棍,所以列得不等式此处求得满足不等式的最小的就是操作一的次数了,将木棍转换成煤炭还需要次操作二,所以本题答案就是了。下面讲一下如何求,显然满足单调性,所以一种方法就是直接进行二分求解,另一种方法就是通过移项,得到,那么最小的就是。
#include<iostream>
#include<cstdio>
using namespace std;
int main(void){
int T;
long long x,y,k;
cin>>T;
while(T--){
scanf("%lld%lld%lld",&x,&y,&k);
printf("%lldn",((y+1)*k-1+x-2)/(x-1)+k);
}
return 0;
}
B. Negative Prefixes
题意:
给出一个长度为的数列,有一些位置被锁定了,对于未被锁定的位置,可以进行重新排列,对于重新排列后的数组记为,现在记录一个前缀和,我们需要找到一个最大的,使得,问如何对数组进行排列,可以使得最小。
思路:
比较明显的一个贪心是,对于未锁定的位置,将其按照降序排序是最优的,下面稍微证明一下:假设按照如此策略得到的前缀和,不难看出无论如何操作,是不变的,那么,,以此类推,我们的目标是为了让的出现位置尽量靠前,也就是让后面的数都尽可能大,观察上面前缀和公式的变形,不难看出让后面的数尽可能小是最优的,所以直接实现即可,实现的话我是用了一个优先队列减少码量,当然去找最小值时间复杂度也是可以的。
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int MAX_N=110;
int a[MAX_N],b[MAX_N];
int main(void){
int T,n,i;
cin>>T;
while(T--){
priority_queue<int>q;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
for(i=1;i<=n;i++){
scanf("%d",&b[i]);
if(b[i]==0)
q.push(a[i]);
}
for(i=1;i<=n;i++){
if(b[i])
printf("%d ",a[i]);
else{
printf("%d ",q.top());
q.pop();
}
}
printf("n");
}
return 0;
}
C. Mortal Kombat Tower
题意:
给出个怪物,1表示高级的怪物,0表示低级的怪物,现在A和B组队去打怪,两个人轮流出招,B的能力比较强,可以随便杀死所有怪物,A的能力较弱,只能杀死低级的怪物,但是A可以使用一个道具用来杀死一个高级怪物,在每个人出招时,至少杀死面前的一个怪物,至多杀死面前的两个怪物,A先开始出招,问如何分配策略,可以使得使用的道具最少就能杀死个怪物。
思路:
贪心去想的话,每次碰到高级怪物让B去击杀肯定是更优的,但需要讨论的情况非常多,而且对于这种无后效性的最优解问题,是一个比较显然的dp问题。设为到了第i个位置,B杀死第i个怪物的最小代价,为到了第i个位置,A杀死第i个怪物的最小代价,那么答案就是了。考虑转移,因为A和B需要轮流上阵,所以dp1只能向dp2转移,同理dp2也只能向dp1进行转移,又因为每次至多击杀两个连续的怪物,所以分类讨论一下就好了,代码中由注释,结合注释应该更好理解。
#include<iostream>
#include<cstdio>
using namespace std;
const int INF=0x3f3f3f3f;
const int MAX_N=201000;
int dp1[MAX_N],dp2[MAX_N],a[MAX_N];
int main(void){
int T,n,i;
cin>>T;
while(T--){
scanf("%d",&n);
for(i=0;i<=n;i++)
dp1[i]=dp2[i]=INF;
dp1[0]=0;//因为A需要进行先手,所以将B初始化为0
for(i=1;i<=n;i++){
scanf("%d",&a[i]);
dp1[i]=min(dp1[i],dp2[i-1]);//B来击杀第i只怪物
if(i>=2)
dp1[i]=min(dp1[i],dp2[i-2]);//B来击杀第i只和第i-1只怪物
dp2[i]=min(dp2[i],dp1[i-1]+a[i]);//A来击杀第i只怪物,如果第i只怪物是高级怪物的话,需要使用道具
if(i>=2)
dp2[i]=min(dp2[i],dp1[i-2]+a[i]+a[i-1]);//A来击杀第i只和第i-1只怪物,同上需要注意道具的使用情况
}
printf("%dn",min(dp1[n],dp2[n]));
}
return 0;
}
D. Trash Problem
题意:
在一维坐标轴上给出堆垃圾,首先规定原本在 x 位置有一堆垃圾,若将其扫到 x - 1 或 x + 1 位置后,会有一个单位的贡献,再规定此时的贡献 ans 为,将所有的垃圾合并为不超过两堆的贡献,现在给出次操作,每次操作会添加一堆新的垃圾或者删除一堆已有的垃圾,每次操作后输出贡献 ans,需要注意的是,题目保证了每堆垃圾的位置都不会相同。
思路:
首先考虑如何快速计算出贡献,假设当前有堆垃圾,若想要合并为一堆的话,无论如何合并,都需要将个相邻的间隔都走一遍,类似的,如果想要合并为两堆的话,只需要遍历个间隔即可,对于同一个状态来说,用表示当前状态下的个间隔之和,若想去掉一个间隔后使得总答案最小,那么显然去掉的间隔越大越好,此时答案就呼之欲出了,我们需要维护的就是和当前个间隔中的最大值,每次贡献的答案就是两者之差了。再考虑如何维护,因为每次给出的垃圾都是在坐标轴上的位置,且我们最终需要维护的间隔,实质上是所有坐标排序后,相邻两个数之差,故我们可以维护一下整个升序的序列,每次在加入新的垃圾 pos 时,找到两个位置 lower 和 upper 分别代表小于 pos 的最大值和大于 pos 的最小值,在加入 pos 后,只会影响到这个间隔,考虑加入 pos 后会造成什么影响:
- lower - upper 之间的间隔消失。
- lower - pos 之间的间隔新增。
- pos - upper 之间的间隔新增。
如此维护一下和所有的间隔即可,删除的话同理,只不过需要将所有操作倒着再来一遍即可。下面考虑如何实现,因为每次操作的时间限制在了,所以我用multiset实现的,一个用来维护原序列,一个用来维护所有的间隔,以及一个全局变量,每次添加或删除一个数,只需要相应的在multiset上二分找到相应位置,维护好答案后相应的删除或增加即可,时间复杂度。值得一提的是,为了防止在查找时造成不必要的越界,可以在初始化时加入相应的哨兵节点,维护时特判一下即可。
#include<iostream>
#include<cstdio>
#include<set>
using namespace std;
const int INF=0x3f3f3f3f;
const int MAX_N=201000;
multiset<long long>st1,st2;
multiset<long long>::iterator lower,upper,it,t;
long long sum;
void add(int pos){
st1.insert(pos);
lower=st1.lower_bound(pos);
upper=lower;
lower--;
upper++;
if(*lower!=-INF&&*upper!=INF){
long long delta=*upper-*lower;
sum-=delta;
st2.erase(st2.find(delta));
}
if(*lower!=-INF){
long long delta=pos-*lower;
sum+=delta;
st2.insert(delta);
}
if(*upper!=INF){
long long delta=*upper-pos;
sum+=delta;
st2.insert(delta);
}
}
void del(int pos){
lower=st1.lower_bound(pos);
upper=lower;
lower--;
upper++;
if(*lower!=-INF){
long long delta=pos-*lower;
sum-=delta;
st2.erase(st2.find(delta));
}
if(*upper!=INF){
long long delta=*upper-pos;
sum-=delta;
st2.erase(st2.find(delta));
}
if(*lower!=-INF&&*upper!=INF){
long long delta=*upper-*lower;
sum+=delta;
st2.insert(delta);
}
st1.erase(st1.find(pos));
}
int main(void){
int n,m,i,op,pos;
scanf("%d%d",&n,&m);
st1.insert(-INF);//哨兵节点
st1.insert(INF);
st2.insert(0);
for(i=1;i<=n;i++){
int pos;
scanf("%d",&pos);
st1.insert(pos);
}
for(it=++st1.begin();it!=st1.end();it++){//扫出所有间隔
t=it;
t--;
if(*t!=-INF&&*it!=INF){
st2.insert(*it-*t);
sum+=*it-*t;
}
}
printf("%lldn",sum-*st2.rbegin());
while(m--){
scanf("%d%d",&op,&pos);
if(op==1)
add(pos);
else
del(pos);
printf("%lldn",sum-*st2.rbegin());
}
return 0;
}
点赞的时候,请宠溺一点
- 实例分享微信小程序项目搭建(上)
- Android6.0源码分析之蓝牙显示接收到的文件
- Android中应用调用系统权限
- Android5.0以后隐式启动ServiceBug
- Android6.0源码分析之录音功能(一)
- Android6.0源码开发之修改默认音量default及max和min
- Android源码开发之添加/删除系统应用
- 按键事件处理
- Android6.0锁屏源码分析之界面布局分析
- Android6.0源码分析之menu键弹出popupwindow菜单流程分析
- Android中初步自定义view
- Android中View研究自学之路 Android6.0源码分析之View(一)Android6.0源码分析之View(二)
- Android蓝牙配对弹出框过程分析 Android蓝牙配对弹出框过程分析
- Android6.0之修改或者查看系统属性值
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android Bitmap压缩方式分析
- Android自定义View实现游戏摇杆键盘的方法示例
- 详解Android Libgdx中ScrollPane和Actor事件冲突问题的解决办法
- Android ImageView的selector效果实例详解
- 完美解决关于禁止ViewPager预加载的相关问题
- Android开发之OpenGL绘制2D图形的方法分析
- Android实现RecyclerView下拉刷新效果
- 详解 Android中Libgdx使用ShapeRenderer自定义Actor解决无法接收到Touch事件的问题
- Android Shader应用开发之雷达扫描效果
- Android开发之绘制平面上的多边形功能分析
- Android Surfaceview的绘制与应用
- Android SQLite数据库版本升级的管理实现
- Android自定义view实现拖拽选择按钮
- Android 中ViewPager中使用WebView的注意事项
- Android IPC机制Messenger实例详解