zoukankan      html  css  js  c++  java
  • 51nod 1686 第K大区间 二分瞎搞

    题目:

    定义一个区间的值为其众数出现的次数。
    现给出n个数,求将所有区间的值排序后,第K大的值为多少。

    题解:

    答案明显单调,我们考虑二分答案.
    转化为判定问题后我们需要观察到一个性质:

    如果一个区间的价值已经 >= mid了,那么这个无论左右端点向外延伸多少,区间价值一定仍然 >= mid

    所以我们可以考虑找出所有的最小满足限制的区间,然后计算出可延伸区间。
    所以我们枚举右端点,根据右端点找出对应的左端点,然后统计答案.
    我们发现:根据右端点向右移动,左端点一定也向右移动。
    所以我们使用双指针法,每一次计算出右端点所代表的值的上mid-1次出现的位置
    用这个位置和左端点指针取max,每一次让ans += 所有<=下标左端点的点的个数.

    单次判定(O(n)),总体(O(nlogn))

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    inline void read(int &x){
    	x=0;char ch;bool flag = false;
    	while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
    	while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
    }
    inline void read(ll &x){
    	x=0;char ch;bool flag = false;
    	while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
    	while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
    }
    const int maxn = 120000;
    int last[maxn],nxt[maxn];
    int b[maxn],n,a[maxn],c[maxn],pos[maxn];
    inline void init(){
    	memset(last,0,sizeof last);
    	memset(nxt,0,sizeof nxt);
    	memset(b,0,sizeof b);
    }
    inline ll check(int val){
    	ll ret = 0;
    	init();memset(c,0,sizeof c);
    	for(int i=1;i<=n;++i){
    		last[i] = c[a[i]];
    		c[a[i]] = i;
    	}memset(c,0,sizeof c);
    	for(int i=n;i>=1;--i){
    		nxt[i] = c[a[i]];
    		c[a[i]] = i;
    	}
    	memset(c,0,sizeof c);
    	memset(pos,0,sizeof pos);
    	for(int i=1;i<=n;++i){
    		if(++c[a[i]] == 1) pos[a[i]] = i;
    		if(c[a[i]] == val) b[i] = pos[a[i]];
    		else if(c[a[i]] > val){
    			b[i] = nxt[b[last[i]]];
    		}
    	}
    	if(val == 1) for(int i=1;i<=n;++i) b[i] = i;
    	for(int L=0,R=1;R <= n;++R){
    		L = max(L,b[R]);
    		ret += L;
    	}
    	return ret;
    }
    int main(){
    	read(n);ll k;read(k);
    	for(int i=1;i<=n;++i){
    		read(a[i]);b[i] = a[i];
    	}
    	sort(b+1,b+n+1);
    	for(int i=1;i<=n;++i){
    		a[i] = lower_bound(b+1,b+n+1,a[i]) - b;
    	}
    	int l = 1,r = n,ans = 0;
    	while(l <= r){
    		int mid = (l+r) >> 1;
    		if(check(mid) >= k) ans = mid,l = mid+1;
    		else r = mid-1;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Eclipse下进行SVN提交时报“svn: Transaction is out of date
    【Spring学习】Spring事物管理之aop技术
    【框架学习】ibatis DAO框架分析
    【maven详解-插件】maven 插件机制
    【maven详解-插件】maven插件学习之maven-source-plugin
    关于使用 no-js (Modernizr)
    白话讲MyIsam和InnoDB的区别
    向鼠标右键菜单增加菜单项
    表单提交按钮input和button、a的差异
    MySQL数据库索引的设计原则
  • 原文地址:https://www.cnblogs.com/Skyminer/p/6601981.html
Copyright © 2011-2022 走看看