尺取法 (入门)

尺取法,顾名思义和尺子一样,一段一段的量过去。和遍历有点类似,但是却时间快于遍历。


看到别人的博客,说尺取法和蚯蚓蠕动类似,先从起点开始,然后直到头到最大范围(即身子拉长到极限),然后在收缩尾巴,再动头部,向前伸展。     


类似的把蚯蚓的尾巴看做数组的起点,把头部看做遍历的进程。    


下面介绍一题,尺取法的入门题。  poj    3061




Description

A sequence of N positive integers (10 < N < 100 000), each of them less than or equal 10000, and a positive integer S (S < 100 000 000) are given. Write a program to find the minimal length of the subsequence of consecutive elements of the sequence, the sum of which is greater than or equal to S.

Input

The first line is the number of test cases. For each test case the program has to read the numbers N and S, separated by an interval, from the first line. The numbers of the sequence are given in the second line of the test case, separated by intervals. The input will finish with the end of file.

Output

For each the case the program has to print the result on separate line of the output file.if no answer, print 0.

Sample Input

2
10 15
5 1 3 5 10 7 4 9 2 8
5 11
1 2 3 4 5

Sample Output

2
3




ac代码:      //  另外补一句,遇见这个容易超时的,尽量不要用cin   cout   改为scanf  和printf  。

#include<iostream>   
#include<cstring>
#define min(a,b) a>b?b:a
using namespace std;
int a[100010];
int main()
{
int t,n,m,i,j,sum;
cin>>t;
while (t--)
{
sum=0;
cin>>n>>m;
for (i=0;i<n;i++)
{
cin>>a[i];
sum+=a[i];
}
if (sum<m)
{
cout<<0<<endl;
continue;
}
sum=0;
int l=0,r=0,res=n+1;
while (r<n)
{
while (sum<m&&l<n)
sum+=a[l++];
if (sum<m)
break;
res=min(res,l-r);
sum-=a[r++]; 

cout<<res<<endl;
}
return 0;

  



链接:https://www.nowcoder.com/acm/contest/84/F
来源:牛客网

题目描述

给定n个数,从中选出三个数,使得最大的那个减最小的那个的值小于等于d,问有多少种选法。

输入描述:

第一行两个整数n,d(1 <= n <= 100,000,1 <= d <= 1000,000,000);
第二行n个整数满足abs(ai) <= 1,000,000,000。数据保证a单调递增。

输出描述:

输出一个整数表示满足条件的选法。

链接:https://www.nowcoder.com/acm/contest/84/F
来源:牛客网

输入

4 3
1 2 3 4

输出

4
示例2

输入

4 2
-3 -2 -1 0

输出

2
示例3

输入

5 19
1 10 20 30 50

输出

1




解法一  ac:



#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
ll a[100010];
int main()
{
int n;
ll d,i,res=0,temp,l,r;
scanf ("%d%lld",&n,&d);
for (i=1;i<=n;i++)
scanf ("%lld",&a[i]);
for (i=1;i<=n;i++)              //   尺取法  (思路简单,但是我写的比较复杂)
{
l=i;
if (l>=n-1)
break;
if (l==1)
r=3;
if (r<=n&&a[r]-a[l]<=d)
{
while (a[r]-a[l]<=d&&r<=n)
r++;
r--;
res=res+(r-l)*(r-l-1)/2;  
}
else if (l<n-1&&a[l+2]-a[l]>d)
continue;
else if (a[r]-a[l]>d) 
{
while (a[r]-a[l]>d)
r--;
}
}
cout<<res<<endl;
return 0;



解法二  ac:



#include<iostream>
#include<cstdio>
#define ll long long
ll a[100010];
int main()
{
    int i,n;
ll d,res,mid,temp;
while (scanf ("%d%lld",&n,&d)!=EOF)
{
res=temp=0;
for (i=1;i<=n;i++)
scanf ("%lld",&a[i]);
for (i=1;i<=n;i++)            //  二分
{
ll l=i,r=n;temp=0;
while (l<=r)
{
mid =(l+r)>>1;
if (a[mid]-a[i]<=d)
{
temp=mid;
l=mid+1;
}
else 
r=mid-1;
}
if (temp!=0&&temp>(i+1))
res=res+(temp-i-1)*(temp-i)/2;
}
printf ("%lld\n",res);
}
return 0;
}


猜你喜欢

转载自blog.csdn.net/a1204675546/article/details/80151757