双指针

(又称尺取法)
是一种优化技巧,可用于解决序列的区间问题

两个指针i,j有两种扫描方向

  1. 反向扫描:i从头到尾,j从尾到头
  2. 正向扫描:j跑在i前面;也称为快慢指针

连续自然数和

p1147
看作升序,i指针指向一段数字的左边,j指针指向右边。sum为和
如果sum<m,右边边界向右边移动,j++,sum+=j
如果sum>=m,若sum==m,则输出i,j
(P.A:这里不能这样,(下左图))

A-B数对

P1102
用k,i,j三个指针
k指针用于枚举每个数
i指针指向a[i]-a[k]=c的一段数的左端
j指针指向a[i]-a[k]=c的一段数的右端
ans维护这段数的个数,ans+=j-i

点击查看代码
void solve()
{
	ll n,c;cin>>n>>c;
	ll a[n+10];
	for(int i=1;i<=n;++i)
	{
		cin>>a[i];
	}
	sort(a+1,a+1+n);
	ll i=1,j=1;ll ans=0;
	for(ll k=1;k<=n;++k)
	{
		while(i<=n&&a[i]-a[k]<c) ++i;
		while(j<=n&&a[j]-a[k]<=c) ++j;
		ans+=j-i;
	}
	cout<<ans<<'\n';
}

逛画展

注意数组范围哇啊啊,最开始开的是ll a[n+10],cnt[n+10],找不到错误,无能狂怒哇,〒▽〒

点击查看代码
#define ll long long
const ll N=1e6+10;
ll a[N];
ll cnt[2010];
void solve()
{
	ll n,m;cin>>n>>m;
	
	for(ll i=1;i<=n;++i)
	{
		cin>>a[i];
	}
	ll len;  //长度
	ll l=0,r=0;   //答案左右编号
	ll num;  //记录当前区间有多少画家
//	ll i=1;
	cnt[a[1]]=1;num=1;len=INT_MAX;
//	cout<<1<<'\n';
	for(ll j=1,i=1;j<=n;)
	{
		if(num<m)
		{
			j++;
			cnt[a[j]]++;
			if(cnt[a[j]]==1) num++;
		}
		if(num==m)
		{
			if(len>j-i+1)
			{
				len=j-i+1;
				l=i;r=j;
			}
			cnt[a[i]]--;
			if(cnt[a[i]]==0)
			{
				num--;
			}
			i++;
		}
		
	}
	cout<<l<<" "<<r<<'\n';
	
}
posted @ 2025-02-02 20:13  YuanqLi  阅读(35)  评论(0)    收藏  举报