BZOJ 3524 [Poi2014]Couriers(二分+蒙特卡罗)

 

【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=3524

 

【题目大意】

  给一个长度为n的序列a。1≤a[i]≤n。
  m组询问,每次询问一个区间[l,r],是否存在一个数在[l,r]中出现的次数大于(r-l+1)/2。
  如果存在,输出这个数,否则输出0。

 

【题解】

  我们可以在[l,r]中随机一个位置检验这个位置上数是不是答案,
  检测方法可以在数组中保存每个数在序列中的不同位置,二分即可
  选中答案的概率为1/2,我们做k次蒙特卡罗,正确率就为1-(1/2)^k,
  复杂度为O(kmlogn)。

  主席树做法见 LINK

 

【代码】

#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int N=500010;
vector<int> pos[N];
int a[N],l,r,n,m;
int main(){
    while(~scanf("%d%d",&n,&m)){
        for(int i=1;i<=n;i++)pos[i].clear();
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);   
            pos[a[i]].push_back(i);
        }
        while(m--){
            scanf("%d%d",&l,&r);
            int len=r-l+1,find=0;
            for(int k=1;k<=20;k++){
                int u=a[l+rand()%len];
                int st=lower_bound(pos[u].begin(),pos[u].end(),l)-pos[u].begin();
                int en=upper_bound(pos[u].begin(),pos[u].end(),r)-pos[u].begin();
                if((en-st)*2>len){find=u;break;}
            }if(find)printf("%d\n",find);
            else puts("0");
        }
    }return 0;
}
posted @ 2017-05-17 16:25  forever97  阅读(143)  评论(0编辑  收藏  举报