首页 > 其他分享 >加练日记2-二分,双指针,排序

加练日记2-二分,双指针,排序

时间:2024-05-12 11:30:53浏览次数:12  
标签:二分 加练 int ll mid long using 指针

  1. 二分
    • 模板
	#include <bits/stdc++.h>
using namespace std;
using ll = long long;

const ll MOD = 998244353;
ll n,m;
const ll N =2e5+9;
ll a[N];
ll v[N];
int f(ll mid){
	ll ans=0,pre=-1e9;
	for(int i=1;i<=n;i++){
		if(a[i]-pre>=mid) ans++,pre=a[i];
	}
	return ans;
}
int main(){
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	sort(a+1,a+n+1);
	ll l=0,r=2*1e9+10;
	//二分模板,我自己学的
	while(l+1!=r){
		ll mid=(l+r) >> 1;
		if(f(mid)>=m) l=mid;
		else  r=mid;
	}
	cout<<l<<' ';
	return 0;
}//这种写法错误概率小	

一般利用二分首先要排序,其次找到方程关于l,r的关系(如牛奶那道题目)。 如果遇到你想找像连续不同最大子串个数可以用二分解决,
但是你要想清楚怎么去寻找,我学到的一种方法是动态去维护子串的最大值,如下(还可以利用双指针,双指针要确保方向不然会超时,就是方向不能出现从两侧分开,双指针的话你需要一个前一个后,并且考虑i,j需不需要从头开始还是保持不变继续往下,代码如下下)

bool check(int mid){
     for(int i=1;i<=n;i++) c[a[i]]=0;
     int cnt1=0;
     for(int i=1;i<=mid;i++){
        c[a[i]]++
        if(c[a[i]]==1) cnt1++;
        else if(c[a[i]]==2)cnt1--;
        if(cnt1==mid) return true;
      }
      //下面这个部分是实时维护子串中为一的个数
      for(int i=1;j=mid;j<n;++i,++j){
        c[a[i]]--;
        if(c[a[i]]==1)cnt1++;
         else if(c[a[i]]==0) cnt1--;
         
        c[a[j+1]]--;
        if(c[a[j+1]]==1)cnt1++;
        else if(c[a[j+1]]==2)cnt1--;
        if(cnt1==mid) return true;
      }
    return false;
}        

就刚刚写的ABC-353,就可以利用二分,当时写的时候找不到思路,我对二分怎么用还是有点问题
(虽然当时想到用二分解决,但是思路错了)。
https://atcoder.jp/contests/abc353/tasks/abc353_c

补题代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

const ll MOD = 100000000;
ll n,m;
const ll N =3e5+9;
ll a[N],v[N];
ll ans=0,sum=0,pd=0;

/*
  
  每个数字都相当于加了(n-1)遍
  ,但是如果出现俩个数相加大于1e8
  ,就要减一个1e8,我们只要将所有的数*n-1·
  然后在计算一下剪掉1e8的个就行,排序
  ,然后二分或者lower_bound都行
 */
int check(int x){
	ll l=0,r=n+1;
	while(l+1!=r){
		ll mid = (l+r) >> 1;
		if(a[mid]>=x) r=mid;
		else l=mid;
	}
	return r;//找每一个数从右边开始数多少个满足。
}
int main(){
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);

	cin>>n;

	for(int i=1;i<=n;i++) {
		cin>>a[i];
	    sum+=(n-1)*a[i];
	}
	 sort(a+1,a+n+1);
	ans=sum;
	for(int i=1;i<n;i++){
		if(a[i]+a[n]<MOD) continue;
		int res=check(MOD-a[i]);
		if(res<=i)res=i+1; if(res>n) continue;
		ans-=(n-res+1)*MOD;
	}
	cout<<ans;

	return 0;
}

*双指针
这个就是从头找到尾巴,看范围如果很大容易超时,双指针写法很多,只能慢慢一个一个去学。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

const ll MOD = 998244353;

const ll N =2*1e5+9;


ll a[N];
ll v[N];
int main(){
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    ll n;
	cin>>n;
	while(n--){
		memset(v,0,sizeof v);
		ll m;
		cin>>m;
		for(int i=1;i<=m;i++)cin>>a[i];
		
		ll ans =0;
		
		for(ll i=1,j=0;i<=m;i++){
		   while(j<m&&!v[a[j+1]])v[a[++j]] ++;
			ans=max(ans,j-i+1ll);
			v[a[i]] --;
		}
		cout<<ans<<'\n';
	}
	return 0;
}

xor前缀和
题目链接https://www.starrycoding.com/problem/53

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

const ll N =2e5+8;

int prexor[N];

void solve()
{
	int a,b;
	cin>>a>>b;
	int y=prexor[a-1]^b;
	if(y==a) cout<<a+2<<'\n';
	else if(y==0) cout<<a<<'\n';
	else  cout<<a+1<<'\n';
}

int main ()
{
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
  for(int i=1;i<=2e5;i++) prexor[i] = prexor[i-1]^i;
	int t;
	cin>>t;
	while(t--) solve();
	return 0; 
}

标签:二分,加练,int,ll,mid,long,using,指针
From: https://www.cnblogs.com/dontian/p/18187422

相关文章

  • 蓝桥杯-递增三元组(三种解法,二分, 双指针, 前缀和)
    给定三个整数数组A=[A1,A2,…AN],B=[B1,B2,…BN],C=[C1,C2,…CN],请你统计有多少个三元组(i,j,k)满足:1≤i,j,k≤NAi<Bj<Ck输入格式第一行包含一个整数N。第二行包含N个整数A1,A2,…AN。第三行包含N个整数B1,B2,…BN。第四行包含N个整数C1,C2,…CN。输出格......
  • 二分图
    1.二分图的概念二分图,又称二部图,英文名叫Bipartitegraph。如果一张无向图的\(N\(N≥2)\)个节点,可以分成A、B两个非空集合,其中\(A∩B=Φ\),并且在同一集合内的点之间都没有边相连,那么称这张无向图为一张二分图。A、B分别称为二分图的左部和右部。如下图所示。2.二......
  • 第8章 指针和引用
    1什么是指针指针是存储内存地址的变量与所有变量一样,指针也占用内存空间,其特殊之处在于,指针包含的值为内存地址,因此,指针是指向内存单元的特殊变量内存单元通常使用十六进制表示法1.1声明指针和其它变量一样,指针在使用前也需要声明。通常将指针声明为指向特定的类型,如int,......
  • C++ const常量指针
    const常量指针const是C++关键字,译为常量,const指针即为常量指针。分为三类指向const的指针const指针指向const的const指针指向const的指针表示指向区域的数据是不可变的,但是可以更换指向语法(将const卸载*之前):const数据类型*指针名数据类型const*指针名......
  • 代码随想录算法训练营第第一天 | 704. 二分查找 、27. 移除元素
    704、二分查找题目链接:https://leetcode.cn/problems/binary-search/文章讲解:https://programmercarl.com/0704.二分查找.html视频讲解:https://www.bilibili.com/video/BV1fA4y1o715`varsearch=function(nums,target){letleft=0;letright=nums.length;letmi......
  • 代码随想录算法训练营第一天 | 704.二分查找 27.移除元素
    704.二分查找题目链接:https://leetcode.cn/problems/binary-search/文档讲解:https://programmercarl.com/0704.二分查找.html视频讲解:https://www.bilibili.com/video/BV1fA4y1o715左闭右开时间复杂度O(logn)空间复杂度O(1)classSolution{public:intsearch(......
  • 二分
    二分浮点数二分模板boolcheck(doublex){/*...*/}//检查x是否满足某种特性doublebsearch_3(doublel,doubler){constdoubleeps=1e-6;while(r-l>eps){doublemid=(l+r)/2;if(check(mid))r=mid;else......
  • 二分查找的个人朴素实用理解
    背景二分查找主要用于在有序数组中查找符合条件的特定值,更进一步可以拓展到查找大于特定值的最小数和小于特定值的最大数的边界值问题,在数据量很大的场景下合理利用有序或者说单调性这一特性大大提高查找效率,能在对数时间内解决问题。虽然理解起来很简单,但是二分法是很常用......
  • 二分法、冒泡排序
    【一】二分法二分法查找,也称为折半法,是一种在有序数组中查找特定元素的搜索算法思路:首先,从数组的中间元素开始搜索,如果该元素正好是目标元素,则搜索过程结束,否则执行下一步。如果目标元素大于/小于中间元素,则在数组大于/小于中间元素的那一半区域查找,然后重复步骤的操作。如......
  • 整体二分
    抽象。P3527[POI2011]MET-MeteorsByteotianInterstellarUnion有\(n​\)个成员国。现在它发现了一颗新的星球,这颗星球的轨道被分为\(m​\)份(第\(m​\)份和第\(1​\)份相邻),第\(i​\)份上有第\(a_i​\)个国家的太空站。这个星球经常会下陨石雨。BIU已经预测了接......