尺取法知识点
概括:尺取法是用两个指针解决问题的算法
题目特征:求满足条件的最小区间
图示:
题意
给定数字序列,求一段连续的尽可能短的子序列,使这个子序列满足条件:和大于等于S。
思路
让两个指针(数组用下标)指向初始位置,left保留在原地,right往右走,直到满足条件。
如果走到序列的最后面都没有满足条件,说明该样例无解,跟它说再见。
如果走到某个位置,满足条件了,那么让right停下来。
这时候我们看看能不能把这个子序列压缩短一点,因为这个子序列刚刚加上了这个子序列中最右边那个数字才使条件满足,所以右边没法压缩。
我们看把left往右移动一位,看看还符不符合条件,符合的话记录,不符合的话,说明压缩之前的是暂时的解,然后继续走right,不断重复上述步骤直到right走到结尾而left无法再压缩就结束。
尺取法的题目
http://poj.org/problem?id=3061**
poj 3061
模板题,按照上面的思路即可求解。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[100005];
int main()
{
int T,n,s;
scanf("%d",&T);
while(T--){
memset(a,0,sizeof(a));
scanf("%d %d",&n,&s);
int l=0,r=0,sum=0,ans=n;
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
while(1)
{
while(r<n&&sum<s)
sum+=a[r++];
if(sum<s)break;
ans=min(ans,r-l);
sum-=a[l++];
}
if(ans==n)printf("0\n");
else printf("%d\n",ans);
}
return 0;
}
http://poj.org/problem?id=2100**
POJ - 2100
题意
题目要我们找到所有的连续数列,使得他们的平方的和等于n
模板题,按照上面写的思路即可求解。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int left[10000000],right[10000000];
int main()
{
long long n;
scanf("%lld",&n);
long long l=1,r=1,ans=0,sum=0;
while(1)
{
while(r<=sqrt(n)+1&&sum<n) {
sum+=r*r;
r++;
}
if(sum<n)break;
if(sum==n)left[ans]=l,right[ans++]=r;
sum-=l*l;
l++;
}
printf("%d\n",ans);
for(int i=0;i<ans;i++){
printf("%d",right[i]-left[i]);
for(int j=0;left[i]+j<right[i];j++)
printf(" %d",left[i]+j);
printf("\n");
}
return 0;
}