Codeforces 982D (模拟+思维+暴力+STL)

链接:http://codeforces.com/problemset/problem/982/D


题目大意:
给你一个长为n的数组.,你可以任意选定一个数字k,使得大于等于k的数变成0,其他数变成1,
然后要满足所有为1的块的大小一样,并且你要保证为1的块尽可能多,问你满足条件的最小的k为多少?

思路:一开始我的想法是明显的二分啊,但是看了看好像难点并不在此,只要简单暴力就行了,O(n)的复杂度,难点在于思考的方法(应该是这样吧,我……太菜了啊)。题目的意思可以等价为不断删去一些数,使得剩下的数的下标连续长度相同,并且要求在块数最大的情况下,求最小的k值。明显的想法是从有序数组的一端(肯定是大的数开始啦^><^)开始暴力一把。不断删去较大的数,放在一个删去数的有序数组sd中,通过找这个大的数的原来的id的块边界,来更新mapp[len]的个数。更新的具体方法:pre-sub的中间的一连续块被id破坏,维护长度的mapp中,删去mapp[长度为pre-sub-1]的块,加上两个mapp[长度分别为sub-cur-1,cur-pre-1的块]。最后完成关于mapp的长度块的统计后,如果mapp的size==1,说明是都是相同长度大小的块,此时满足第一个要求,判断一下第二个要求(块数尽量多,更新一下),第三个要求(k的值要尽可能小,因为我们是从后遍历的。,所以这个要更新一下)。


总结:希望以后做到类似的这种题目能够好好分析出要点(最近发现我总是不会写稍难的暴力),太菜的,弱弱更需要努力,多思考多总结,会好起来的,然后有空希望总结一下常用的stl。
代码:


int main(){
 int n;
 scanf("%d",&n);
 for(int i=1;i<=n;i++){
  scanf("%d",&a[i]);
  s.insert (pii(a[i],i));
 }
 sd.insert (0);
 sd.insert (n+1);//小技巧吧,值得思考哦
 mapp[n]=1;
 int ans=s.rbegin ()->first +1;//最初始的情况是删除0个数,也就是所有的书都是0,也就是ans(k)=右边最大的数+1;
 int cnt=1;//有几个块
 for(int i=0;i<n-1;i++){//至少要有一个1块,所以最多拿掉n-1个数
  auto it=s.rbegin ();//auto,取最右边的位置
  int cur=it->second;//当前取走的数在原来的位置编号
  s.erase (*it);
  int pre=*(--sd.lower_bound (cur));
  int sub=*(sd.upper_bound (cur));
  if(sub-pre-1>0){
   mapp[sub-pre-1]--;
   if(mapp[sub-pre-1]==0){
    mapp.erase (sub-pre-1);
   }
  }
  sd.insert (cur);
  if(cur-pre-1>0)mapp[cur-pre-1]++;
  if(sub-cur-1>0)mapp[sub-cur-1]++;
  if(mapp.size ()==1){
   int num=mapp.begin ()->second ;
   if(num>=cnt){
    cnt=num;
    ans=s.rbegin ()->first +1;
   }
  }
 }
 printf("%d",ans);
}

另附上一种骚逼并查集代码(居然可以用并查集!!!学习学习)
https://blog.csdn.net/weixin_39453270/article/details/80391161

猜你喜欢

转载自blog.csdn.net/running_acmer/article/details/80406781