牛客周赛 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;
} 

胡帅加油!!!

posted @ 2025-04-16 19:41  LteShuai  阅读(7)  评论(0)    收藏  举报