尺取
顾名思义就是像尺子一样去截取一段数据判断是否满足题目要求想要的条件。
通常靠采用下标保存左右端点,然后根据需求改变下标移动左右端点,来避免进行重复运算,最终来获得答案。
尺取并不是万能,有些情况可以用,有些情况不可以用,要仔细审题判断是否能用尺取算法。
如下题
http://120.78.162.102/problem.php?cid=1546&pid=0
描述
冬日里的一抹暖阳总是能给人们留下深刻的记忆,人们喜爱冬天的太阳,就跟人们喜爱冬天的火锅一般。
寒冷的冬天总会让人想起火锅,最近小Z特别想去吃火锅,刚好某家转转火锅刚开业有活动,有n盘火锅围成一个圈,第一盘和最后一盘是相连的,每一盘火锅都有一个价值a[i],现在可以吃连续的m盘火锅,小Z想知道他所吃的那连续的m盘火锅的最大价值可以是多少?你能帮帮憨憨的小Z吗。
格式
输入格式
第一行数入两个整数n,m(1<=m<=n<=2000000),分别表示火锅的盘数和可以吃的连续的盘数
第二行输入n的数a[i](1<=a[i]<=100000),分别表示每一盘火锅的价值
输出格式
输出一个整数,表示连续m盘火锅的最大价值
样例
样例输入 Copy
5 3 6 1 2 5 3
样例输出 Copy14
题目很明显,在一群数中找连续的m个最长子序列,但是首尾是相连的,此题如果用暴力做输入定义数组大小N再开一个数组计算每m个连续火锅价值选出最大价值明显时间会超限,因为最大情况为2000000*2000000。
所以我们可以用尺取。不需要进行重复运,比如算出前M的火锅价值后只需保存这个值然后减去第一个火锅的值,再加上后一个火锅的值,算神似于KMP算法。首先定义一个sum接受前M中火锅的价值,后面运用尺取来一步步推进比较当前M的火锅价值与SUM进行比较让SUM更新为最大值,然后判断条件看是否要到首尾相加的情况再另外运算。如图所示:
代码如下:
#include<stdio.h> #include<string.h> int main() { long long int n,s; while(scanf("%lld%lld",&n,&s)!=EOF) { long long int num[n+1]; for (int i=1;i<=n;i++) scanf("%lld",num+i); long long int j=0, w=0 , sum=0, ans=n+1; for(int i=1;i<=s;i++) sum+=num[i]; j=2; long long int zs=sum; while(j<=n-s+1) //不需要首位相加 { zs-=num[j-1]; zs+=num[j+s-1]; if(sum<zs)sum=zs; j++; } long long int dd=1; //下标从一开始 while(j<=n) //需要首位相加 { zs-=num[j-1]; zs+=num[dd]; dd++; if(sum<zs)sum=zs; j++; } printf("%lld\n",sum); } return 0; }
来源:https://www.cnblogs.com/johnfllora/p/12208993.html