牛客周赛 45 D 补题 双指针

前言
搞半天 思考半天 以为是和逛画展那个题一样的单调队列题目 然而是我想太多了 其实这就是个双指针 我要把这个题深深烙印在我的脑海里
思路
其实这个money trees 这个题的双指针写法极其的相似 , 本题是一个从前往后的枚举思维 money trees 其实也是 这样才好用双指针嘛 均摊下来On的时间
然后就是 我for循环 那里l写成l=r+1 这是没彻底理解算法本质才会这么写的 首先你要明白 这个r是什么
这个r是当前l最远延深的地方 跟l++没关系 l++也要算区间的,我以前做过一个数组延深的玩意 就是
a[i]=r r就是最远延申的下标 此题其实也是这么个思路
但是是这么个思路没错 但是我们要做到这个区间所有的数 都要延申正确 所以要用到lastcolour数组 做到时刻更新last的位置 如此才可以 比money trees难上一些 因为要用到这个last 数组
为了更好解释这一份让我一直挂念在心上从开学到现在的题目 我会好好讲透它
让我们给出一份样例 更好的解释它把
6 2
1 2 3 4 2 1
我看牛客直播写的那份代码
始终解释不透这一句
if(last[col[l]]==l)
last[col[l]]=0;
其实当你把这个样例看懂就明白了

首先我造这个样例就是为了检查这个2隔了k看看代码实际运行,于是我就明白了 原来是这样的一个思路
就是它只对l,r 卡死了l为基准 然后算l,r的区间数 当然l自己也算一个
于是有 1,12,123,1234
再就是对于这跟2 隔了2的2 于是r不动了直接统计了23 24
就下一步了
然后来到3
继续进行程序
那么对于那一句代码是什么意思呢
为什么弄成0呢
因为对于最后那个1它不用管之前那个1,为什么呢?因为很明显,中间出现了不能连接因为那两个2,于是我就明白 选区间不可能有123456这样的 肯定断开了 那么我这个1总不能和你上一个1有关联吧?
于是为了没关联
上一个1到while结束都没碰到下一个1但是为了不影响它
(r+1=下一个1的下标时候,因为这两个一剪是>k的)选区间于是只好把它弄成0就行了
总结
这代码思路真好!!!
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int range=2e5+10;
int n;
int k;
int col[range];
int last[range];
void solve()
{
//我太笨了
想歪了 哪知道一个On就可以了
还想用滑窗为k去写 结果写崩了
//这种双指针写了无数道了
自己还是不能一做到就写出来 真废物
cin>>n>>k;
int ans=0;
for(int i=1;i<=n;i++)cin>>col[i];
int r=0;
for(int l=1;l<=n;l++)
{
while(r<n&&((r+1&&!last[col[r+1]])||(r+1&&r+1-last[col[r+1]]<=k)))
{
r++;
last[col[r]]=r;
}
if(last[col[l]]==l){
last[col[l]]=0;
}
ans+=r-l+1;
// cout<<l<<" "<<r<<" "<<ans<<endl;
}
cout<<ans<<endl;
}
signed main()
{
ios::sync_with_stdio();
cin.tie(0);
cout.tie(0);
solve();
return 0;
}

浙公网安备 33010602011771号