当前位置:   article > 正文

hdu6602 hdu多校第二场 1012 尺取/数据结构/思维

hdu6602

题解线段树做法没看懂.

但是有个更巧妙的数据结构做法:(orz想出这种方法的大佬)

主要思路是尺取.

先扫右端点,肯定是判断这个数a[r]的总可能出现次数是否大于等于k,如果不,区间肯定不可能包括r.

如果大于的话,扩展区间..并记录这个小区间中每种出现的数.出现的次数.pnum

和出现次数为a的数有b个.(用map记录,map存储是按第一个key的小大顺序存储,所以我们找第一个map对应的一个key一定是,出现次数最少的数的出现次数a.如果大于等于k不就说明我们维护的这个区间满足题意嘛);

然后更新左端点,每次判断小区间是否满足,同样更新pnum[],和map.

 

然后注意了!!   我们先在r是在不能更新的点上,所以++,而l也要跳过这个点,

但在跳过之前要把num[a[r]]--,虽然这个a[r]的num对后面不会产生影响了.但为了下次多组数据的初始化,还是更新一下.

这样就省去了初始化的时间.

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. char ssssss[30];
  4. inline int Read()
  5. {
  6. int x=0,f=1; char ch=getchar();
  7. while (ch<'0'||ch>'9') {if (ch=='-') f=-f; ch=getchar();}
  8. while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
  9. return x*f;
  10. }
  11. inline void writeln(int x)
  12. {
  13. if (x<0) putchar('-'),x=-x;
  14. if (!x) putchar('0'); else
  15. {
  16. int len=0;
  17. while (x) ssssss[++len]=x%10+'0',x/=10;
  18. while (len) putchar(ssssss[len--]);
  19. }
  20. putchar('\n');
  21. }
  22. typedef long long ll;
  23. typedef long double ld;
  24. typedef pair<int,int> pii;
  25. typedef pair<ll,ll> pll;
  26. typedef pair<ld,ld> pdd;
  27. #define F first
  28. #define S second
  29. const int M = 1e5 + 10;
  30. const ll INF64=8000000000000000000LL;
  31. const int INF=0x3f3f3f3f;
  32. const ll MOD=ll(1e9+7);
  33. const ld PI=acos(-1);
  34. const ld eps=1e-9;
  35. using namespace std;
  36. int num[M];//每种数出现的次数
  37. int a[M];
  38. int pnum[M];//尺取维护的区间每个数出现的个数
  39. int main()
  40. {
  41. ios::sync_with_stdio(false);
  42. cin.tie(0);
  43. int n,c,k;
  44. map<int,int>mp;//mp[a][b]代表:所维护的区间中,数字出现次数为a的数字有b个
  45. while(cin>>n>>c>>k)
  46. {
  47. for(int i=1;i<=n;i++)
  48. cin>>a[i],num[a[i]]++;
  49. int l=1,r=1;
  50. int ans=0;
  51. mp.clear();
  52. while(l<=n)
  53. {
  54. //printf("%d--%d\n",l,r);
  55. while(r<=n&&num[a[r]]>=k)//如果这个数出现次数可能大于k
  56. {
  57. mp[pnum[a[r]]]--;//因为a[r]有出现了一次,所以要把 之前的更新
  58. if(mp[pnum[a[r]]]==0) mp.erase(pnum[a[r]]);//节省空间
  59. pnum[a[r]]++;//出现次数+1
  60. mp[pnum[a[r]]]++;//更新 map
  61. r++;//接着往右走
  62. }
  63. //往右走到头了,处理左边的端点。
  64. while(l<r)
  65. {
  66. mp.erase(0);//防止这种情况干扰判断
  67. if(mp.begin()->first>=k)
  68. //mp中第一个元素的第一个key,即出现次数最小的出现次数。(map是按a的小大顺序存的)
  69. {
  70. ans=max(ans,r-l);
  71. }
  72. mp[pnum[a[l]]]--;//更新
  73. if(mp[pnum[a[l]]]==0) mp.erase(pnum[a[l]]);//节省空间
  74. pnum[a[l]]--;
  75. mp[pnum[a[l]]]++;
  76. num[a[l]]--;
  77. l++;
  78. //因为端点右移,以后不再访问,所以a[l] 数字的出现次数-1
  79. }
  80. // l=r+1;//因为a[r]是不满足条件的,所以l直接从r+1开始
  81. num[a[r]]--;//这里--的目的是减少初始化的时间开销。
  82. r++;
  83. l=r;
  84. }
  85. printf("%d\n",ans);
  86. }
  87. return 0;
  88. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/180244
推荐阅读
相关标签
  

闽ICP备14008679号