尺取法经典例题

 连续子序列

给定一个长度为N(10<N<100000)的正整数序列。每个正整数都小于等于10000,给定一个正整数S(S<100000000)。编写一个程序找到一个最小长度的子序列,要求这个子序列的和大于等于S。如果解不存在,则输出0。

输入格式

第一行两个整数N和S,第二行包括n个正整数表示数列A,两两之间用空格分隔。

输出格式

一个符合题目要求的整数。

输入/输出例子1

输入:

5 11

1 2 3 4 5

输出:

3

代码:
#include<bits/stdc++.h>
using namespace std;
long long a[10000005],sum,s,n,ans;
int main(){
    cin>>n>>s;
    for(int i=0;i<n;i++)
        cin>>a[i];
    int tou=0,wei=0,ans=10000000,sum=0;
    while(1)
    {
        while(wei<n&&sum<s)
            sum+=a[wei++];
        if(sum<s)break;
        ans=min(ans,wei-tou);
        sum-=a[tou++];
    }
    if(ans==10000000)cout<<0;
    else cout<<ans;
    
    return 0;
}

最小和

输入N个数的数列,所有相邻的M个数的和共有N-M+1个,求其中的最小值。

输入格式

第1行,2个整数N,M,范围在[3…100000],N>M。

第2行,有N个正整数,范围在[1…1000]。 

输出格式

1个数,表示最小和。 

输入/输出例子1

输入:

6 3

10 4 1 5 5 2

输出:

10

代码:
#include<bits/stdc++.h>
using namespace std;
long long n,m,s,a[100005],mins=0x7f7f7f7f7f7f7f7f;
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int L=1,R=1;R<=n;R++)
    {
        s+=a[R];
        if(R-L+1==m)
        {
            mins=min(mins,s);
            s=s-a[L];
            L++;
        }
    }
    cout<<mins;
    return 0;
}

求和为C

楠楠在网上刷题,感觉第一题:求两数的和(A+B Problem)太无聊了,于是增加了一题:求和为C的Problem,难倒了一群小朋友,哈哈。 题目是这样的:给出N个正整数,一个值C,要求在这N个整数中找一段连续的数(至少2个数),使得它们的和等于C,问这样的方案有多少种? 例如:N=8,C=7,8个整数是:2 5 1 1 2 4 7 1。答案是3。具体方案:(2, 5)、(5,1,1)、(1,2,4)。

输入格式

第一行2个正整数:N,C。

第二行:N个正整数。

数据范围:N的范围是[1…100,000]。C的范围是[1…1,000,000,000]。N个整数中每个数的范围是:[1…1,000,000,000]。

输出格式

一个整数,表示该串数中包含的所有方案数。

输入/输出例子1

输入:

4  5
1  4  1  4

输出:

3

代码:
#include <bits/stdc++.h>
using namespace std;
int n,m,k,a[100005],s[100005],ans;
int main() {
	scanf("%d%d",&n,&m);
	for(int i=1; i<=n; i++)
    {
		scanf("%d",&a[i]);
		s[i]=s[i-1]+a[i];
	}
	for(int i=1;i<=n;i++)
    {
		for(int j=i+1;j<=n;j++)
        {
			if(s[j]-s[i-1]==m)
				ans++;
			if(s[j]-s[i-1]>=m)
				break;
		}
	}
	printf("%d\n",ans);
	return 0;
}

附一道同一类型的题

楠楠在网上刷题,感觉第一题:求两数的和(A+B Problem)太无聊了,于是增加了一题:A-B Problem,难倒了一群小朋友,哈哈。
题目是这样的:给出 N 个从小到大排好序的整数,一个差值 C,要求在这 N个整数中找两个数 A 和 B,使得 A-B=C,问这样的方案有多少种?
例如:N=5,C=2,5 个整数是:2 2 4 8 10。答案是 3。具体方案:第3个数减第 1 个数;第 3 个数减第 2 个数;第 5 个数减第 4 个数。

输入格式

第一行 2 个正整数:N,C。
第二行 N 个整数:已经有序。注意:可能有相同的。

输出格式

一个整数,表示该串数中包含的所有满足 A-B=C 的数对的方案数。

输入/输出例子1

输入:

4  1
1  1  2  2

输出:

4

样例解释

5 个数据:N 的范围是[1…1,000]。
5 个数据:N 的范围是[1…100,000]。
所有数据:
C 的范围是[1…1,000,000,000]。
N 个整数中每个数的范围是:[0…1,000,000,000]。

代码:
#include<bits/stdc++.h>
using namespace std;
long long n,c,a,t;
map<long long,long long>b;
int main()
{
    cin>>n>>c;
    for(int i=1;i<=n;i++)
    {
        cin>>a;
        if(c<=a)t+=b[a-c];
        b[a]++;
    }
    cout<<t;
   
    return 0;
}

黑白奶牛

有N只奶牛从左往右排成一行,编号是1至N。这N只奶牛当中,有一些奶牛是黑色的,其余的是白色的。

color[i]表示第i只奶牛的颜色,如果color[i]=0则表示第i头奶牛是黑色的,如果color[i]=1则表示第i头奶牛是白色的。

六一奶牛儿童节快到了,农场主Farmer John要从这N头奶牛当中,挑选尽可能多的奶牛去参加晚会。

Farmer John挑选奶牛的原则是:挑选编号是连续的一段奶牛,这一段奶牛的颜色必须全部是白色的。

Farmer John有一个魔法棒,每用一次魔法棒就可以把一头黑色的奶牛变成一头白色的奶牛,魔法棒最多只能使用K次。在上述条件下,最多可以有多少头奶牛去参加晚会呢?

输入格式

第一行,两个整数,N和K。

第二行,N个整数,第i个整数就是color[i],color[i]要么是0,要么是1。

输出格式

一个整数,表示最多有多少头奶牛可以去参加晚会。

数据规模

对于50%的数据,1<=N<=1000,K=0,即不能使用魔法棒。

对于100%的数据,1<=N<=100000,1<=K<=N。

输入/输出例子1

输入:

11 0 

1 1 0 0 1 1 1 1 0 1 1

输出:

4

输入/输出例子2

输入:

11 1 

1 1 0 0 1 1 1 1 0 1 1

输出:

7

样例解释

样例1 由于 K=0,所以不能使用魔法棒, 所以挑选编号是 5 至 8 的奶牛去参加晚会

样例2 由于 K=1,所以最多可以使用 1 次 魔法棒,使用魔法棒把第 9 头奶牛 变成白色奶牛,然后挑选编号是 5 至 11 的奶牛去参加晚会。

代码:
#include<bits/stdc++.h>
using namespace std;
int a[100010],n,k,l=1,r=1,ans=0,sum=0;
int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    while(r<=n)
    {
        if(!a[r++])sum++;
        while(sum>k)
            if(!a[l++])sum--;
        ans=max(ans,r-l);
    }
    cout<<ans;
    return 0;
}

拔河比赛

今天小Q班的体育课,是进行拔河比赛。同学们个个兴奋极了。体育老师一声令下,就抢着拉绳子占好了位置,谁也不肯让谁。

每位同学都一个力量值,为了让两边队伍实力均衡,体育老师想找一个合适的“中点”,将队伍分成两边,使得两个队伍力量总值相差最小。你来帮体育老师想想办法?

输入格式

第一行有两个正整数。一个整数N(2 <= N <= 500000),表示小Q班上的人数。

第二行有N个整数,依次表示队伍中每位同学的力量值P(0<=p<=1000)。

输出格式

输出两个数x和y。 表示在x和y之间设置“中点”,可以使队伍两边的力量总值相差最小(如果有多个中点,则以x大优先)。

输入/输出例子1

输入:

10

65 50 80 85 120 95 85 55 75 120

输出:

5 6

样例解释

前5个人的力量和为400,后5个人的力量和为430,最小差值为30。

数据范围:

对于60%的数据    N<10000;

对于100%的数据  N<500000;

代码:
#include<iostream>
using namespace std;
int a[1001000],b[1001000];
long long n,sum,num,maxx,f;
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		sum+=a[i];
	}
	for(int i=1;i<=n;i++)
	{	
        num+=a[i];
		b[i]=abs(sum-num-num);
	}
	maxx=b[1];
    f=1;
	for(int i=1;i<n;i++)
	{
		if(maxx>=b[i])
		{
			maxx=b[i];
			f=i;
		}
	}
	cout<<f<<" "<<f+1;
    return 0;
 } 

射箭

FJ很喜欢看射箭比赛,看着运动员们一个个精湛的技艺,令他头晕目眩膜拜不已。而且他喜欢给那些射箭选手打分,他想如果一位选手能在尽量短的时间段内射出所有可能的环数,那么他的得分就是那段最短时间的长度。
现在,FJ告诉你其中一位选手共射出了n支箭,当然他每个单位时间射出一只箭。FJ还会告诉你他射出的每支箭的环数。而且环数总共的可能性有m种,环数分别为1-m,请你帮他算过这位选手在他心目中的分数。

输入格式

输入文件共两行
第一行两个数n,m。
第二行一共n个数表示那位选手每一箭的环数。

输出格式

输出文件只有一个数,表示这位选手的得分。如果这位运动员无法在这n箭中射出所有的环数,则输出-1。

输入/输出例子1

输入:

12 5
2 5 3 1 3 2 4 1 1 5 4 3

输出:

6

样例解释

说明:这位选手从第2支箭到第7支箭射出了所有可能的环数,因此他的得分是6。

数据范围

30% n<=1000 m<=20

100% n<=1000000 m<=2000

代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,a[1000005],b[2005],ans,minn=1000000001;
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int x=1,y=1;y<=n;y++)
    {
        b[a[y]]++;
        if(b[a[y]]==1) ans++;
        while(ans==m)
        {
            minn=min(minn,y-x+1);
            b[a[x]]--;
            if(b[a[x]]==0)ans--;
            x++;
        }
    }
    if(minn!=1000000001)cout<<minn;
    else cout<<"-1";
    
    return 0;
}

收集数据

幼儿园的N名(N为偶数)小朋友们排成一列,每个人手中都拿有一个数据fi,两位老师分别站在队首和队尾。一个从队首往中间走,一位从队尾往中间走,他们俩走的节奏始终一致,直到相遇为止。在行进的过程中,他们每人可以收集连续K个小朋友手上的数据,但必顺在同一时刻开始,同一时刻结束。求这个过程被收集的数据之和最大可能是多少。

输入格式

幼儿园的N名(N为偶数)小朋友们排成一列,每个人手中都拿有一个数据fi,两位老师分别站在队首和队尾。一个从队首往中间走,一位从队尾往中间走,他们俩走的节奏始终一致,直到相遇为止。在行进的过程中,他们每人可以收集连续K个小朋友手上的数据,但必顺在同一时刻开始,同一时刻结束。求这个过程被收集的数据之和最大可能是多少。

输出格式

输出为一行,是一个整数,为被收集的小朋友手中数据之和的最大值。

输入/输出例子1

输入:

8 2
1 1 5 1 2 4 3 1

输出:

13

代码:
#include<bits/stdc++.h>
using namespace std;
int n,k,a[1000005],sum,b[1000005],num,maxx;
int main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        b[i]=a[i]+b[i-1];
    }
    for(int i=1,j=i+k-1,x=n,y=x-k+1;j<y;i++,j++,x--,y--)
        maxx=max(maxx,(b[j]-b[i-1])+b[x]-b[y-1]);
    cout<<maxx;
    return 0;
}

最少页数

为了准备比赛,华华开始读一本很厚的书本。要想通过考试,必须把书本中所有的知识点都掌握。这本书共有P页,每一页都有一个知识点Ai。全书中同一个知识点可能会被多次提到,所以他希望通过阅读其中连续的一些页把所有的知识点都覆盖到。请你求出要阅读的最少页数。

输入格式

第一行,1个整数P,1<=P<=10^6

第二行,P个正整数Ai,1<=Ai<=10^6

输出格式

输出要阅读的最少页数

输入/输出例子1

输入:

5

1 8 8 8 1

输出:

2

样例解释:

只需要阅读第一页和第二页即可

代码:
#include<bits/stdc++.h>
using namespace std;
int n,a[1000005],b[1000005],tou=0,wei=0,c[1000005],sum,s,bj=1000000000;
int main(){
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
        if(b[a[i]]==0){b[a[i]]=1,sum++;}
    }
    for(tou=0,wei=0;wei<n;wei++)
    {
        if(c[a[wei]]==0)s++;
        c[a[wei]]++;
        while(s==sum)
        {
            bj=min(bj,wei-tou+1);
            c[a[tou]]--;
            if(c[a[tou]]==0)
                s--;
            tou++;
        }
    }
    cout<<bj;
    return 0;
}

最短子串

给出字符串S,字符串的每一个字符是’1’或’2’或’3’。你要从S中选取一段连续字符,不妨假设这段连续的字符构成的字符串是T,你的目标是使得T的长度最短,而且字符’1’、’2’、’3’在T中都出现过。如果无法完成目标则输出0,否则输出T的最短长度。

输入格式

一个字符串S,长度不超过200000。

输出格式

 一个整数。

输入/输出例子1

输入:

112233

输出:

4

数据范围

对于60%的分数,S的长度不超过100。

代码:
#include<bits/stdc++.h>
using namespace std;
string a;
int tou=0,wei=0,c[1000005],sum=3,s,bj=1000000000;
int main(){
    cin>>a;
    for(tou=0,wei=0;wei<a.size();wei++)
    {
        if(c[int(a[wei])]==0)s++;
        c[int(a[wei])]++;
        while(s==sum)
        {
            bj=min(bj,wei-tou+1);
            c[int(a[tou])]--;
            if(c[int(a[tou])]==0)
                s--;
            tou++;
        }
    }
    cout<<bj;
    return 0;
}

  • 14
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值