题目链接:http://oj.daimayuan.top/course/22/problem/59

板子题:
- #include
- using namespace std;
- const int N=2e6+10;
- int a[N],n,q;
-
- int calc1(int x){//查找第一个小于x的位置
- int L=0,R=n+1;
- while(L+1
- int mid=L+R>>1;
- if(a[mid]
- else R=mid;
- }
- return L;
- }
-
- int calc2(int x){//查找第一个小于等于x的位置
- int L=0,R=n+1;
- while(L+1
- int mid=L+R>>1;
- if(a[mid]<=x) L=mid;
- else R=mid;
- }
- return L;
- }
-
- inline void solve(){
- cin>>n>>q;
- for(int i=1;i<=n;i++) cin>>a[i];
- sort(a+1,a+1+n);
- while(q--){
- int x;cin>>x;
- int x1=calc1(x),x2=calc2(x);
- cout<
" "<" "<"\n"; - }
- }
-
- int main(){
- solve();
- }
题目链接:http://oj.daimayuan.top/course/22/problem/61

题意:给定一个长度为N的数组,以及最大操作次数K,求经过M次操作后使得数列中的最小值最大。
思路:要想使得最小值最大,那么一定是经过了K次操作,这里直接二分答案,通过答案来求解操作数
代码:
- #include
- using namespace std;
- const int N=2e6+10;
- int a[N],n,k;
-
- bool check(int x){//检查答案是否符合条件
- int ans=0;
- for(int i=1;i<=n;i++)
- ans+=max(0,x-a[i]);
- return ans<=k;
- }
-
- int main(){
- cin>>n>>k;
- for(int i=1;i<=n;i++) cin>>a[i];
- int L=0,R=n+1;
- while(L+1
//二分答案 - int mid=L+R>>1;
- if(check(mid)) L=mid;
- else R=mid;
- }
- cout<
- }
题目链接:http://oj.daimayuan.top/course/22/problem/649

方法: 二分,怎么二分?
因为把所有序列给合并起来,再算和,是一定会TIE的。
如果可以求出每个序列都能满足条件的和,再把所有序列的和加起来,就好了。
那么我们找出了位置,如何求和呢?
直接采用等差数列的公式进行O(1)求和:n*(a1+an)/2
代码:
- #include
- #define int long long
- using namespace std;
- const int N=2e5+10;
- int n,k[N],b[N],m;
-
- int calc(int z){//计算边界L左边小于等于z的个数
- int res=0;
- for(int i=1;i<=n;i++){
- if(z>=b[i]){
- //kx+b=z--->x=(z-b)/k
- int y=(z-b[i])/k[i]+1;//记录个数
- //为什么要加1,是因为每组序列中,都存在x=0的情况
- res+=y;//记录个数
- }
- }
- return res;
- }
-
- int sum(int z){
- int res=0;
- for(int i=1;i<=n;i++){
- if(z>=b[i]){
- int y=(z-b[i])/k[i] + 1;//记录项数
- res+=1LL*((b[i]+(y-1)*k[i]+b[i])*y/2);//记录每个序列中的和
- //等差数列求和公式:n*(a1+an)/2
- }
- }
- return res;
- }
-
- signed main(){
- cin>>n;
- for(int i=1;i<=n;i++) cin>>k[i]>>b[i];
- cin>>m;
- int L=0,R=1e14;//R尽可能的大
- while(L+1
//二分 - int mid=L+R>>1;
- if(calc(mid)<=m) L=mid;
- else R=mid;
- }
- int ans=sum(L)+1LL*((m-calc(L))*(L+1));//最终答案
- cout<
- }
浮点数二分:
这里稍微讲一下:浮点数二分其实和整数二分是差不多的。唯一不同点在于:整数的二分次数是不确定的,而浮点数二分一般是能够算出来的,但是浮点数二分一般二分100次就可以了。
题目链接:http://oj.daimayuan.top/course/22/problem/648

思路:二分答案。对于方向移动问题,我们可以考虑成区间的问题解答。
举个例子:a b人在两个不同点,他们要达到目标点,给定两人的速度,问最少能够到达?
我们发现,只要两人跑到路程区间有交集,那么就可以到达,最少时间为跑的慢的人刚好到达目标点的时间。
那么为什么跑的快的人不会超过目标位置呢?
因为跑的快的人到达目标点后,是可以原地踏步的,就相当于在原地跑。(奇怪的知识又增加了Q_Q)
同理:多人跑目标位置,也是一样的道理。每一次都要改变交集,以保持最优情况
代码:
- #include
- using namespace std;
- const int N=2e5+10;
- int n;
- int pos[N],v[N];
-
- bool check(double x){
- double L=-1e10,R=1e10;//初始区间尽可能大
- for(int i=1;i<=n;i++){
- double l=pos[i]-v[i]*x,r=pos[i]+v[i]*x;//求左右距离
- L=max(L,l);R=min(R,r);//求交集
- }
- if(L>R) return false;//若无交集
- return true;//有交集
- }
-
- signed main(){
- cin>>n;
- for(int i=1;i<=n;i++) cin>>pos[i]>>v[i];
- double L=0,R=5e4;//定义二分时间的区间//需根据题意自行判断区间
- for(int i=1;i<=100;i++){//二分次数100次
- double m=(L+R)/2;
- if(check(m)) R=m;
- else L=m;
- }
- cout<
setprecision(10)<//输入L,R都可以 - }
二分+哈希求字符串最长回文子串的长度,我们秉着最优的方法,这里就不讲了。
二分+哈希:O(nlogn) manacher:O(n)
题目链接:http://oj.daimayuan.top/course/22/problem/698
二分求Lis(最长上升子序)也不讲了。秉着最优原则
-
相关阅读:
ASP.NET Core使用记录3
信号处理之巴特沃斯滤波器的理解----2022/11/30
JDK 21的新特性总结和分析
【Webpack】CSS 处理
Raymarching(光线步进)基础
OpenGL笔记九之彩色三角形与重心插值算法
Spring-Cloud-OpenFeign源码解析(上篇)
OpenCV类VideoCapture构造函数中参数apiPreference的可选值及意义
Python 基于 selenium 实现不同商城的商品价格差异分析系统
常用软件快捷键
-
原文地址:https://blog.csdn.net/YuDuna/article/details/127802224