ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

cf1514 D. Cut and Stick

2022-04-28 01:01:59  阅读:198  来源: 互联网

标签:Cut cf1514 int 绝对 pos 次数 Stick 众数 define


题意:

给定数组。q 次询问,每次问至少把 \(a[l,r]\) 拆成几个子序列,才能让每个子序列中的众数的出现次数 不大于子序列长度/2上取整

\(n,q\le 3e5, 1\le a_i\le n\)

思路:

绝对众数:出现次数严格大于N/2

如果区间众数不是绝对众数,则答案为1。否则,设绝对众数的出现次数为 x

,把其他所有数(共 n-x 个)和 n-x+1 个绝对众数分一组,剩下的绝对众数每个单独一组,组数是 x-(n-x+1)+1=2x-n。这样就是最优的!(真的)

众数可以用莫队求。但根据绝对众数的性质,还有些其他方法

法一:随机

绝对众数的出现次数大于一半,随便选一个数,它不是绝对众数的概率约 1/2,随机选40次左右就很稳,每次选出来都二分求出现次数

实测随机40次要2秒,30次1.7秒,25次居然wa

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
ll ran(ll l, ll r) {
	return uniform_int_distribution<int>(l,r)(rng);
}

const signed N = 3 + 3e5;
int n, q, a[N]; vector<int> pos[N];

int cnt(int l, int r, int x) { //x在区间中的出现次数
    return upper_bound(all(pos[x]),r) - lower_bound(all(pos[x]),l);
}

signed main() {
    iofast;
    cin >> n >> q; for(int i = 1; i <= n; i++)
        cin >> a[i], pos[a[i]].pb(i);

    while(q--) {
        int l, r; cin >> l >> r;
		int ans = 0; for(int i = 1; i <= 30; i++)
			ans = max(ans, cnt(l,r,a[ran(l,r)]));
        cout << max(1, 2*ans-(r-l+1)) << endl;
    }
}

法二:线段树

绝对众数肯定也是至少一个儿子的绝对众数

节点维护区间的绝对众数

查询可谓非常暴力啊。所有走过的区间的绝对众数都作为候选,每个都求(在整个大区间中的)出现次数,取max返回

复杂度俩log,不到一秒

const signed N = 3 + 3e5;
int n, q, a[N]; vector<int> pos[N];

int cnt(int l, int r, int x) { //x在区间中的出现次数
    return upper_bound(all(pos[x]),r) - lower_bound(all(pos[x]),l);
}

#define mid ((l+r)/2)
#define lson u*2
#define rson u*2+1
#define ls lson,l,mid
#define rs rson,mid+1,r
int tr[N<<2]; //区间众数
void build(int u, int l, int r) {
    if(l == r) tr[u] = a[l];
    else build(ls), build(rs),
tr[u] = cnt(l,r,tr[lson]) > cnt(l,r,tr[rson]) ? tr[lson] : tr[rson];
}
int ask(int u, int l, int r, int x, int y) { //返回区间绝对众数的出现次数
    if(y < l || x > r || y<x) return 0; //没交集
    if(x <= l && r <= y) return cnt(x,y,tr[u]); //包含
    return max(ask(ls, x, y), ask(rs, x, y));
}

signed main() {
    iofast;
    cin >> n >> q; for(int i = 1; i <= n; i++)
        cin >> a[i], pos[a[i]].pb(i);

    build(1, 1, n);

    while(q--) {
        int l, r; cin >> l >> r;
        cout << max(1, 2*ask(1,1,n,l,r)-(r-l+1)) << endl;
    }
}

标签:Cut,cf1514,int,绝对,pos,次数,Stick,众数,define
来源: https://www.cnblogs.com/wushansinger/p/16201283.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有