Comet OJ - Contest #16 小 C 的可重集 (随机二分)(线段树)

2024-01-30 01:08

本文主要是介绍Comet OJ - Contest #16 小 C 的可重集 (随机二分)(线段树),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

传送门

  • 秀儿操作!我们每次随一个区间,考虑求出 ≥ \ge 它的区间个数
    注意到左端点固定区间大小随右端点递增,于是 ≥ \ge 一个区间的是一个前缀
    如果个数 ≥ k \ge k k 那么可以给每一个左端点的区间钦定一个上界,否则可以钦定一个下界
    这样的期望次数是 log ⁡ n \log n logn 的,相当于每次 b a n ban ban 掉一部分
    于是问题变成了对于给定区间,对每一个左端点求前缀的终止位置使得这个前缀 ≥ \ge 给点区间
    这个位置单调,于是我们可以 t w o p o i n t e r two\ pointer two pointer 扫一下,线段树维护值域
#include<bits/stdc++.h>
#define cs const
#define pb push_back
using namespace std;
typedef long long ll;
template <typename T> T read(){T cnt=0, f=1; char ch=0;while(!isdigit(ch)){ ch=getchar(); if(ch=='-') f=-1; }while(isdigit(ch)) cnt=cnt*10+(ch-'0'), ch=getchar();return cnt*f;
}
std::mt19937 rn(time(0));
std::uniform_int_distribution<int> rnd(0,(int)1e9);
int gi(){ return read<int>(); }
ll gl(){ return read<ll>(); }
cs int N = 1e5 + 50;
int n, a[N]; ll k;
int lim[N];
namespace SGT{cs int M = 1<<17;int c[M<<1|5]; bool les[M<<1|5];void clr(){ memset(c,0,sizeof(c));memset(les,0,sizeof(les));}void pushup(int x){c[x]=c[x<<1]|c[x<<1|1];les[x]=les[x<<1]|(!c[x<<1]&&les[x<<1|1]);}void add(int x, int v){if(!x) return;c[x+=M]+=v; les[x]=c[x]<0;for(x>>=1;x;x>>=1) pushup(x);}
}
ll work(int l, int r){SGT::clr(); ll ct = 0;for(int i=l; i<=r; i++) SGT::add(a[i],1);for(int i=1; i<=n; i++){lim[i]=max(i-1,lim[i-1]);while(!SGT::les[1]&&lim[i]<=n) SGT::add(a[++lim[i]],-1);if(i<=lim[i]) SGT::add(a[i],1);ct += (ll)lim[i]-i;} return ct;
}
int main(){n=gi(), k=(ll)n*(n+1)/2-gl()+1;for(int i=1; i<=n; i++) a[i]=gi();static int st[N]; int tp=0; static int L[N], R[N];for(int i=1; i<=n; i++)st[++tp]=i, L[i]=i, R[i]=n;int T = 80;while(T--){int c=st[rnd(rn)%tp+1];int t=L[c]+rnd(rn)%(R[c]-L[c]+1);if(work(c,t)>=k) for(int i=1; i<=tp; i++) R[st[i]]=min(R[st[i]],lim[st[i]]-1);else for(int i=1; i<=tp; i++)L[st[i]]=max(L[st[i]],lim[st[i]]);int ct=0; for(int i=1; i<=tp; i++) if(L[st[i]]<=R[st[i]]) st[++ct]=st[i]; tp=ct; if(tp==1&&L[st[1]]==R[st[1]]) break;}int l=st[1], r=R[st[1]];sort(a+l,a+r+1);for(int i=l; i<=r; i++) cout<<a[i]<<" ";return 0;
}

这篇关于Comet OJ - Contest #16 小 C 的可重集 (随机二分)(线段树)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/658670

相关文章

使用C#如何创建人名或其他物体随机分组

《使用C#如何创建人名或其他物体随机分组》文章描述了一个随机分配人员到多个团队的代码示例,包括将人员列表随机化并根据组数分配到不同组,最后按组号排序显示结果... 目录C#创建人名或其他物体随机分组此示例使用以下代码将人员分配到组代码首先将lstPeople ListBox总结C#创建人名或其他物体随机分组

hdu2241(二分+合并数组)

题意:判断是否存在a+b+c = x,a,b,c分别属于集合A,B,C 如果用暴力会超时,所以这里用到了数组合并,将b,c数组合并成d,d数组存的是b,c数组元素的和,然后对d数组进行二分就可以了 代码如下(附注释): #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<que

hdu2289(简单二分)

虽说是简单二分,但是我还是wa死了  题意:已知圆台的体积,求高度 首先要知道圆台体积怎么求:设上下底的半径分别为r1,r2,高为h,V = PI*(r1*r1+r1*r2+r2*r2)*h/3 然后以h进行二分 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#includ

poj3468(线段树成段更新模板题)

题意:包括两个操作:1、将[a.b]上的数字加上v;2、查询区间[a,b]上的和 下面的介绍是下解题思路: 首先介绍  lazy-tag思想:用一个变量记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率。 比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果刚好执行到一个子节点,

hdu1394(线段树点更新的应用)

题意:求一个序列经过一定的操作得到的序列的最小逆序数 这题会用到逆序数的一个性质,在0到n-1这些数字组成的乱序排列,将第一个数字A移到最后一位,得到的逆序数为res-a+(n-a-1) 知道上面的知识点后,可以用暴力来解 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#in

hdu1689(线段树成段更新)

两种操作:1、set区间[a,b]上数字为v;2、查询[ 1 , n ]上的sum 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>#include<map>#include<stdio.h>#include<stdl

hdu 1754 I Hate It(线段树,单点更新,区间最值)

题意是求一个线段中的最大数。 线段树的模板题,试用了一下交大的模板。效率有点略低。 代码: #include <stdio.h>#include <string.h>#define TREE_SIZE (1 << (20))//const int TREE_SIZE = 200000 + 10;int max(int a, int b){return a > b ? a :

hdu 1166 敌兵布阵(树状数组 or 线段树)

题意是求一个线段的和,在线段上可以进行加减的修改。 树状数组的模板题。 代码: #include <stdio.h>#include <string.h>const int maxn = 50000 + 1;int c[maxn];int n;int lowbit(int x){return x & -x;}void add(int x, int num){while

poj 2976 分数规划二分贪心(部分对总体的贡献度) poj 3111

poj 2976: 题意: 在n场考试中,每场考试共有b题,答对的题目有a题。 允许去掉k场考试,求能达到的最高正确率是多少。 解析: 假设已知准确率为x,则每场考试对于准确率的贡献值为: a - b * x,将贡献值大的排序排在前面舍弃掉后k个。 然后二分x就行了。 代码: #include <iostream>#include <cstdio>#incl

poj 3104 二分答案

题意: n件湿度为num的衣服,每秒钟自己可以蒸发掉1个湿度。 然而如果使用了暖炉,每秒可以烧掉k个湿度,但不计算蒸发了。 现在问这么多的衣服,怎么烧事件最短。 解析: 二分答案咯。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <c