C++算法-尺取法考题

今天我给大家出一套C++算法-尺取法考题

限时50分钟小时,大家加油!!!

尺取法.理论知识(不是题目)

记 (l,r) 两个端点为一个序列内以 l 为起点的最短合法区间,如果 r 随 l 的增大而增大的话,我们就可以使用尺取法。

具体的做法是:

  1. 初始化左右端点

  2. 不断扩大右端点,直到满足条件

  3. 如果第二步中无法满足条件,则终止,否则更新结果

  4. 将左端点扩大1,然后回到第二步

因为 r 随 l 增大而增大,所以 r 只有 n 次变化的机会,所以时间复杂度为 O(n) 。

经典例子

给定一个长度为 n 的数列 a_1, a_2, ..., a_na1​,a2​,...,an​ 及整数 S ,求不小于 S 的连续子序列的和的最小值,假设解肯定存在。

input

n=10,S=15

a= {5,1,3,5,10,7,4,9,2,8}

题目1:队伍(NHOI2016xy6)

题目描述

蛋糕分好了,小朋友排着队去领蛋糕。铭铭想从 N 人的队伍中选出 K 位小朋友帮忙分发蛋糕。但铭铭选人的方法有点特别,他想从队伍中选连续的 K 个小朋友,而且必须是男比女多,你知道铭铭有多少种选择吗?

输入格式

第一行,两个整数 N,代表队伍中有 N ( 0 < N <= 1000000 )个小朋友,铭铭想选 K ( K < N )个人。

第二行:有 N 个 0 或 1(0 代表男,1 代表女),每个数用空格隔开。

数据范围

50% 的数据 0 < N < 1000 , k < N ;

80% 的数据 0 < N < 1000000 , k <= 100 ;

100% 的数据 0 < N < 1000000 , k < N ;

输出格式

一个整数。代表铭铭可以有多少种选择方案。

样例

输入数据 1

10 3
0 1 1 0 1 0 0 1 0 1

输出数据 1

4

完成程序

#include<bits/stdc++.h>
using namespace std;
int n,k,a[1000002],c=0;
long long ans;
int main()
{
	cin>>n>>k;
	
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		a[i]+=a[i-1];  //求女孩子数的前缀和 
	}
	
	for(int x=1,y=填空(1);y<=填空(2);x++,填空(3) ) // k个人位置不断往右挪
	{
		int s=a[y]-a[x-1]; //s表示从 x 到 y 的女孩子个数 
		if(填空(4)>s) c++; //总人数减女孩,就是男孩。如果男生数量大于女生,合条件。 
	}

	cout<<c;

	return 0;
}

Copy

填空(1): 

填空(2): 

填空(3): 

填空(4): 

题目2:松果(DLOI2016xjt) 

题目描述

大森林有熊兄弟的好朋友松鼠蹦蹦,一天蹦蹦来到一条很长的小 路,发现沿路地上都有松果,高兴极了,决定尽可能多吃松果。

蹦蹦观察到,每个松果的重量并不一定相同,可蹦蹦的肚子容量 有限,总共最多只能吃重量 C 的松果。
蹦蹦吃东西有个特点,一旦开吃就会不停的吃,不会漏过路上碰 到松果,直到遇到一个吃不下或吃完停止。也就是说松鼠蹦蹦只会吃 连续一段的松果。

已知路上共有 N 个松果,顺序的重量是 w_1, w_2,..., w_nw1​,w2​,...,wn​ 。蹦蹦最多可能吃多少颗松果?

输入格式

第一行,二个正整数,空格分开,表示 N 和 C,N 范围在[1..50000], C 范围在[1..1000000]。

第二行,N 个正整数,空格分开,表示从 w_1、w_2,..., w_nw1​、w2​,...,wn​ ,即松果的重量。每个松果重 量范围在[1..1000]。

数据范围

一个正整数,蹦蹦可以吃到的最多松果数量。

输出格式

样例

输入数据 1

5 5
3 1 2 1 1

输出数据 1

4

输入数据 2

9 5
1 5 4 3 2 1 1 4 1

输出数据 2

3

样例解释

样例 1 :吃:(1,2,1,1)这段的松果。

样例 2 :吃:(2,1,1)这段的松果。

完成程序

#include<bits/stdc++.h>
using namespace std;
int n,c,a[50002],ma=0,s=0;
long long ans;
int main()
{
	cin>>n>>c;
	
	for(int i=1;i<=n;i++) cin>>a[i];
	
	for(int x=1,y=填空(1);y<=n;y++)
	{
		s += 填空(2); // x 到 y 的松果总重量
		填空(3) (s>c) s-= a[x++];  //移动 x 收缩区间
		ma=max(填空(4),ma);  //求最长区间长度 
	}

	cout<<ma;

	return 0;
}

填空(1): 

填空(2): 

填空(3): 

填空(4): 

题目3:求和为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

输出数据 1

3

题目4: 黑白奶牛(NHOI2016xjt4)

题目描述

有 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

输出数据 1

4

输入数据 2

11 1
1 1 0 0 1 1 1 1 0 1 1

输出数据 2

7

样例解释

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

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

题目1答案:

代码

'1': k
'2': 'n'
'3': y++
'4': k-s

题目2答案: 

代码

'1': '1'
'2': a[y]
'3': while
'4': y-x+1

题目3答案: 

代码

#include<bits/stdc++.h>
using namespace std;
int n,c,a[100002],ma=0,m=0;
long long ans;
int main()
{
	cin>>n>>c;
	for(int i=1;i<=n;i++) cin>>a[i];
    ma=ma+a[1];
	for(int x=1,y=2;y<=n;y++)
	{
		ma+=a[y];
		while(ma>c) 
        {
            ma-=a[x++];
        }
        if(ma==c&&y-x>0)
        {
            ans++;
        }
	}
	cout<<ans;
	return 0;
}

题目4答案: 

代码

#include<bits/stdc++.h>
using namespace std;
int n,l,k,b[100000],a[100000],sum=0,ma=0;
int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++)
    {
        cin>>b[i];
        a[i]=a[i-1];
        if(b[i]==0) a[i]++;
    }
    for(int i=1;i<=n;i++)
    {
        if(a[i]-a[l]<=k)
        {
            sum++;
            if(i==n&&sum>ma)
            {
                ma=sum;
            }                
        }
        else
        {
            if(sum>ma)
            {
                ma=sum;
            }
            l++;
        }
    }
    cout<<ma;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值