Codeforces1514 D. Cut and Stick(区间众数个数,莫队算法)

题意:

给定长度为n的序列a,q次询问,
每次询问给定L,R,你可以将[L,R]中的数放进若干个盒子,
要求满足每盒子中的众数出现次数<=(盒子中数总数+1)/2,
问最少需要多少个盒子。

数据范围:n,q<=3e5,a(i)<=n

解法:
[l,r]的长度为len,众数个数为cnt,那么非众数个数x=len-cnt.

x个非众数可以和x+1个众数放在一起,满足条件,
多出来的众数只能一个一个放了,个数为cnt-(x+1).

因此需要的总个数为cnt-(len-cnt+1)+1=cnt*2-len.

计算区间众数我用的莫队算法.
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=2e6+5;
const int block=2000;
struct QQ{
    int l,r,id;
}Q[maxm];
int a[maxm];
int res[maxm];
int cnt[maxm];
int cnt2[maxm];
int n,q;
int ans;
bool cmp(QQ a,QQ b){
    if(a.l/block!=b.l/block)return a.l<b.l;
    return a.r<b.r;
}
void add(int x){
    cnt[a[x]]++;
    cnt2[cnt[a[x]]]++;
    if(cnt2[cnt[a[x]]]==1)ans++;
}
void del(int x){
    cnt2[cnt[a[x]]]--;
    if(cnt2[cnt[a[x]]]==0)ans--;
    cnt[a[x]]--;
}
void solve(){
    cin>>n>>q;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=1;i<=q;i++){
        int l,r;cin>>l>>r;
        Q[i]={l,r,i};
    }
    sort(Q+1,Q+1+q,cmp);
    int l=Q[1].l,r=l-1;
    for(int i=1;i<=q;i++){
        int ql=Q[i].l,qr=Q[i].r;
        while(l>ql)add(--l);
        while(r<qr)add(++r);
        while(l<ql)del(l++);
        while(r>qr)del(r--);
        int len=qr-ql+1;
        int t=(len+1)/2;
        if(ans<=t)res[Q[i].id]=1;
        else res[Q[i].id]=ans*2-len;
    }
    for(int i=1;i<=q;i++){
        cout<<res[i]<<endl;
    }
}
signed main(){
    ios::sync_with_stdio(0);
    solve();
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值