kauaiの水题记录——二分
1. 中位数#
第一眼看这道题,想到可以先开一个数组,每加入一个数就用去排序,然后取中间的数,复杂度是,所以可以使用,因为支持在数组中随意插入一个数,所以我们只要找到这个数在哪里就行了,进而想到可以二分,然后就可以了。
这里介绍一下
#include <vector>//头文件
vector<int> s;
s.push_back(a);//尾部插入
s.pop_back();//尾部删除
vertor<int>::iterator it;//声明迭代器
int k=*s.begin();//s.bejin()会返回第一个元素的迭代器,可以用*解除引用
s.insert(s.begin()+i,a)//在第i+1个元素中插入a
s.erase(s.begin()+1)//删除第二个元素
s.erase(s.begin()+i,s.end()+j)//删除区间[i,j-1],区间从零开始
int y=*upper_bound(a.begin(),a.end(),x)//查找第一个大于x的数
2. 山#
题目中说要我们找最小的y坐标,想到可以二分答案,接着想如何判断二分出来的情况是否合法,把每两个相邻折点连成的线段想象成一个一次函数,如果灯的位置在每条直线的上方就是合法的,作一条的直线,和每条一次函数就会有交点,限制灯的横坐标的范围然后进行分类讨论,如果,显然横坐标要在交点的左边,反之同理,要注意的是我们还要判断的清况,此时要注意的就是纵坐标的,因为灯一定要比这条直线高,最后判断范围是否合法即可。我们可以预处理出每条直线的以此来减小常数,要注意实数域上的二分。
while(l+eps<r){
double mid=(l+r)/2.0;
if(check(mid)){
r=mid;
ans=mid;
}
else l=mid;
}
一般eps要比题目要求的精度多两位。
3. 弹幕考察#
这道题如果理解了题意还是比较简单的,可以看作是一个区间覆盖问题,首先我们可以打一个的暴力,对于每一次询问都去枚举每一区间,看是否满足要求,然后累加答案,这样可以拿30分。
其实我们可以把每一个区间都看作两个端点,并开一个数组记录位置,询问的时候二分查找中第一个大于等于查询区间右端点的数的位置,中第一个大于等于查询区间左端点数的位置,然后相减就行了。
4. 赛道修建#
这道题我也不是太懂,就随便口胡一下,想到二分答案,二分最小的赛道长度,对于每一个结点,我们可以存一个,从下往上传,然后放进中,分两种情况讨论,如果说明这个点和它的子树已经可以满足条件了,答案+1,否则就把当前这条边放进中,接着看第二种情况,以这个点为根的子树的两条边相加会大于等于,贪心地想,两个数是不是越小越好,因为我们要把大的数上传到上面去,所以我们可以在里二分去找这个数,然后把这两个点删除,,找不到就和要上传的进行比较,要说明一下,因为一个子树肯定只有一条边连接着上面的结点,所以要去找。最后判断是不是大于就可以知道是不是合法的了。
核心代码:
int dfs(int x,int fa,int k){
s[x].clear();
int val;
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(y==fa) continue;
val=dfs(y,x,k)+edge[i];
if(val>=k) tot2++;
else{
s[x].insert(val);
}
}
int Max=0;
while(!s[x].empty()){
if(s[x].size()==1) return max(Max,*s[x].begin());
it=s[x].lower_bound(k-*s[x].begin());
if(it==s[x].begin()&&s[x].count(*it)==1) it++;
if(it==s[x].end()){
Max=max(Max,*s[x].begin());
s[x].erase(s[x].find(*s[x].begin()));
}
else{
tot2++;
s[x].erase(s[x].find(*it));
s[x].erase(s[x].find(*s[x].begin()));
}
}
return Max;
5. [SHOI2015]自动刷题机#
说实话,这道题真的比较水,感觉不值得评蓝,题目要我们求最大和最小值,所以想到二分,我们可以二分两次,然后对着题意模拟判断是否合法就行了。
比较难的就是如何二分最大和最小值了,其实就是把放到或区间里了。
while(l<=r){
int mid=(l+r)>>1;
int Quick_kk=check(mid);
if(Quick_kk<=k){//求最小值
r=mid-1;
if(Quick_kk==k){ans1=mid;}
}
else l=mid+1;
}
l=1,r=1e18;
while(l<=r){//求最大值
int mid=(l+r)>>1;
int Quick_kk=check(mid);
if(Quick_kk>=k){
l=mid+1;
if(Quick_kk==k){ans2=mid;}
}
else r=mid-1;
}
6. [JXOI2017]加法#
首先二分答案,操作后的最小值,接着贪心地想,除非一定要加,否则就不加,我们可以开一个优先队列,里面存放每个区间的右端点,列举到当前的数时,就在右端点最大的区间里加,因为左边的数已经加完了,用差分维护区间加法,最后判断操作次数是否小于等于 ,和操作完后是否大于等于最小值。
7. [POI2013]LUK-Triumphal arch#
首先二分最小的 ,然后统计每个结点下一级儿子的个数存在中,用 数组统计以x为根的字数内需要支援的次数,初始化为 ,如果数组大于 则向上传,如果小于零也没什么用,因为是从上往下染色的,最后判断是否小于等于 。
8. [HEOI2016/TJOI2016]排序#
可以拿 分!
二分第 位上的数到底是什么,考虑 ,把序列里大于等于 的数改为 ,其余为 ,这样排序时只需要改变 的位置即可,显然可以用线段树维护,最后判断第 位上的数是否为 ,是则为合法的答案,因为为 则说明,二分求出 的最大值也就是等于 的情况。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现