军训场V题-双指针( Codeforces Round #898 (Div. 4) F. Money Trees 题解)
1.自我介绍
作为一个刚敲代码没有多久的的小蒟蒻,也是第一次发博客😂,有一些没说好的地方希望各位大佬谅解,如果存在错误的地方也希望大家可以指出,那么话不多说,action!🌟
2.题目
3.分析题目
根据观察题目我们不难发现Luca所能得到的子数组的数得满足两个条件:
1.高度h[i]能被下一个高度h[i]整除(最后一个数因为后面没有数了,得舍弃)。
2.子数组里的所有a[i]相加不能超过k。
这思路不就来了吗,对数组里的数进行两个条件的判断,如果满足条件子数组个数每次加一,否则子数组个数固定,下一个数返回循环重新判断,直接暴力做。(代码乱写的,但大概意思就是这样)
if(h[j]%h[j+1]==0){ //第一个条件
for(int k=i;k<=j;k++){ //i为子数组的起始下标
sum+=a[k];
if(sum<=m){ //第二个条件
cnt++; //条件满足后,子数组个数加一
}else{
b[l]=cnt; //建立一个数组存储每一个子数组的个数
l++;
cnt=0; //不要忘记个数清零
}
}
当然我们写起来肯定比想起来要难,反正我是没暴力出来😹,就算暴力出来也可能会超时,哎,只能去请教圈圈学长了!
4.题目方法-双指针
其实我们思考一下这题就类似于一种滑动窗口,就像一根辣条,我们每次切中间的一段吃,看那一段切的最长,我们要求的就是那一段的长度,这就需要动态处理区间-双指针!
双指针算法
双指针算法是一种常用的算法技巧,主要用于处理数组和链表等线性结构。它通过使用两个指针(索引位置)来遍历数据结构,从而达到减少时间复杂度的目的。双指针算法有多种变体,包括快慢指针、对撞指针和滑动窗口等。
下面是我从网上找的一段与我们题目类似快慢双指针的题目与代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
string a; //定义一个字符串a
getline(cin,a); //忽略空格读入所有字符
int n=a.size(); //n为a字符串的长度
for(int i=0;i<n i++) //字符串下标都是从0开始
{
int j=i; //j为快字符,i为慢字符
while(a[j]!=' ') j++; //如果没读到空格,j继续向前移动
for(int k=i; k<j;k++) cout<<a[k]; //把i到j中间的字符输出
cout<<endl; //记得换行
i=j; //循环体执行完后for()中的i才i++即,下一次开始时i就到了上一次空格(位置j)的下一位了
}
return 0;
}
我尽力了,如果大家还没搞懂的话可以双指针算法-CSDN博客看看。
5.题目讲解
从题目着手,我们一个一个条件来。
1.高度h[i]能被下一个高度h[i]整除(最后一个数因为后面没有数了,得舍弃)。
2.子数组里的所有a[i]相加不能超过k。
首先我们先判断第一个条件。
while(j+1<n&&h[j]%h[j+1]==0) j++;
我们可以用一个while循环判断数组有多少满足第一个条件的数,j为满足第一个条件的数的个数,至于j+1<n是因为数组的长度是n并且数组最后一个数我们得舍弃。
其次,我们我们继续从j个数里面筛选出满足条件二的数的个数
int sum=0; //sum为总数的大小
for(int k=i,last=i;k<=j;k++) //k为快指针下标,last为慢指针下标,i为起始下标(初始值),j为终止下标(结束值)
{
sum+=a[k];
while(sum>m) //如果我们加的数字超过了k值(我定义的m是题目中的k值)
{
sum-=a[last]; //sum每次减去慢指针下标的数,直到总数小于k值为止
last++; //快指针向右移动,缩小慢指针与快指针的距离
}
ans=max(ans,k-last+1); //ans每次循环更新为最长子数组的长度,k-last+1就是两个指针之间的距离
}
i=j; //因为前面的数已经判断过了,下次指针从j后面一个数开始判断
我从示例一中的第一个样例分析一下
t:5 m:12
a:3 2 4 1 8//注意看这一组
h:4 4 2 4 1
我们最开始让i为0(第一个数4的下标为0,第二个数4为1,第三个数2为2,以此类推),j为0(从0开始计数),前面的4,4,2是满足条件一的,所以j=3.
1.第一次循环sum+a[0]=3,不大于m,进入下一个循环。
快指针 3 2 4
慢指针 3 2 4
2.第二次循环sum+a[1]=5,不大于m,进入下一个循环。
快指针 3 2 4
慢指针 3 2 4
3.第三次循环sum+a[2]=9,不大于m,结束循环。
快指针 3 2 4
慢指针 3 2 4
ans=2-0+1=3
所以输出为3。
示例一中的第二个样例也差不多
注意:但如果进入了while循环,慢指针就向右移动了,反正退出while循环后也是使其满足条件二,再进入max函数。
6.AC代码
累死我了,给大家看看我的AC代码😂
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
typedef long long ll;
const int N=2e5+10;
int a[N],h[N];
int main()
{
IOS;
int t,n,m;
cin>>t;
while(t--){
cin>>n>>m;
int ans=0,cnt=0;
for(int i=0;i<n;i++){
cin>>a[i];
}
for(int j=0;j<n;j++){
cin>>h[j];
}
for(int i=0;i<n;i++){
int j=i;
while(j+1<n&&h[j]%h[j+1]==0)j++;
int sum=0;
for(int k=i,last=i;k<=j;k++){
sum+=a[k];
while(sum>m){
sum-=a[last];
last++;
}
ans=max(ans,k-last+1);
}
i=j;
}
cout<<ans<<endl;
}
return 0;
}
哎,大差不差吧。
其实敲代码真的很累,但需要大家一起坚持,在此我很感谢圈圈学长,苏希无学姐,肖明阳学长,潜水大佬室友等人长期以来给予我的帮助,让我可以坚持下来,最后☆*: .。. o(≧▽≦)o .。.:*☆😘