双指针算法、位运算、离散化

y总yyds 专栏收录该内容
8 篇文章 0 订阅

双指针算法

板子

int j;
for(int i=0,j=0;i<n;i++)
{
	while(j<i&&check(i,j)) j++;
	//具体题目逻辑
}
最长连续不重复子序列

#include<bits/stdc++.h>
using namespace std;
int n;
const int N=1e5+10;
int a[N],s[N];
int res;
int main()
{
	scanf("%d",&n);
	for(int i=0;i<n;i++)	scanf("%d",&a[i]);
	
	for(int i=0,j=0;i<n;i++)
	{
		s[a[i]]++;
		
		while(j<=i&&s[a[i]]>1){
			// 如果有一个数出现了两次,说明这不是一个不重复的子序列了,就开始移动j指针来删除重复的数字
			s[a[j]]--;
			j++;
		}
		res=max(res,i-j+1);
	}	
	cout<<res<<endl;
	return 0; 
} 

位运算

常用
n的二进制数的k位是多少
ans = n >> k & 1

计算二进制中1的个数

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

int lowbit(int x)  // 得到最后一位1 
{
	return x&-x;
	/*
	x&-x =   x&(~x+1)
	
	x=1010.....1000000
	
   ~x=0101.....0111111
   
 ~x+1=0101.....1000000
 
x&(~x+1)=0000.....1000000
	
	*/
}
int main()
{
	int x;
	int res=0;
	scanf("%d",&x);
	while(x){
	x-=lowbit(x),res++;
	}
	cout<<res<<endl; 
	return 0;
}

离散化

用于数据下标大但是数据个数少
板子

vector<int> alls; // 存储所有待离散化的值
sort(alls.begin(), alls.end()); // 将所有值排序
alls.erase(unique(alls.begin(), alls.end()), alls.end());   // 去掉重复元素

// 二分求出x对应的离散化的值
int find(int x) // 找到第一个大于等于x的位置
{
    int l = 0, r = alls.size() - 1;
    while (l < r)
    {
        int mid = l + r >> 1;
        if (alls[mid] >= x) r = mid;
        else l = mid + 1;
    }
    return r + 1; // 映射到1, 2, ...n
}

// y总的板子0.0

例题 Acwing 区间和

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII; // 利用pair来存入 
int n,m;
const int N=300010;   
// 因为要进行n次插入操作并且进行m次查询操作,
//每次查询两个数,所以一共是n+2m个数,
//并且alls中是直接存入要离散化的数也就是也要存入n+2m个数
//所以要开到n+2m  300000

int a[N],s[N];  // s用来做前缀和 
vector<int> alls;  // 代离散化的数组 
vector<PII> adds,query;	// 进行查询与增添操作 
int find(int x){  // 找到x的位置 
	
	int l=0,r=alls.size()-1;
	while(l<r){
		
		int mid=(r+l)>>1;
		if(alls[mid]>x)	r=mid;
		else l=mid+1; 
	}
	return r+1; // 方便前缀和 
} 
int main()
{
	scanf("%d %d",&n,&m);
	
	for(int i=0;i<n;i++){
		int x,c;
		cin>>x>>c;
		adds.push_back({x,c});  // 把坐标为x的数加上c 
		alls.push_back(x);  //把x存入alls
		 
		 // 3 1 3
		 /*
		3 3
		1 2
		3 6
		7 5
		1 3
		4 6
		7 8
		 */
	} 
	for(int i=0;i<m;i++){
		int l,r;  // 读入要查询的区间 
		cin>>l>>r;
		query.push_back({l,r});
		 
		alls.push_back(l);
		alls.push_back(r);
		//3 1 3  1 3 4 6 7 8
		
		
	}
	// 排序加去重 
	sort(alls.begin(),alls.end());
	alls.erase(unique(alls.begin(),alls.end()),alls.end());  
	
	// 1 3 4 5 6 7
	
	//插入处理
	for(auto item:adds){
		
		int x=find(item.first);
		a[x]+=item.second;
	}
	
	for(int i=1;i<=alls.size();i++) s[i]=s[i-1]+a[i];  // 前缀和 
	
	//查询
	for(auto item : query){
		long unsigned int l=find(item.first);
		long unsigned int r=find(item.second);
		cout<<s[r]-s[l-1]<<endl;
		
	} 
	 
	return 0;
}


  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:深蓝海洋 设计师:CSDN官方博客 返回首页

打赏作者

Fluent!

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值