尺取法(又称双指针)是算法竞赛中常用的一个优化技巧,用来解决序列区间问题。
扫描序列时,一般做法会使用二重循环O(n方),尺取法会将两个循环优化为一个,从而达到O(n)的时间复杂度。在尺取法中,i和j有两种扫描方向:反向扫描和同向扫描。
以洛谷p1102 A-B数对为例:
#include<bits/stdc++.h>
using namespace std;
long long sum;
bool f;
int a[400000];
int main() {
int n,c;
cin>>n>>c;
for(int i = 0; i < n; i++)
cin>>a[i];
sort(a,a+n);
for(int i = 0, j = 0, k = 0; i < n; i++)
{
while(a[j] - a[i] < c && j < n) j++;
while(a[k] - a[i] <= c && k < n) k++;
sum += k - j;
}
cout<<sum;
return 0;
}
再以codeforces Dora and Search为例:
#include<bits/stdc++.h>
#define N 3000000
#define ll long long
using namespace std;
int t,n,a[N];
int main()
{
cin>>t;
while(t--)
{
scanf("%d",&n);
for(int i = 1; i <= n; i++) scanf("%d",&a[i]);
int max = n,min = 1,l = 1,r = n;
while(l < r)
{
if(a[l]==max)
{
max--;
l++;
}
else if(a[l]==min)
{
min++;
l++;
}
else if(a[r]==max)
{
max--;
r--;
}
else if(a[r]==min)
{
min++;
r--;
}
else break;
}
if(l < r) cout<<l<<" "<<r<<endl;
else cout<<-1<<endl;
}
return 0;
}