返回顶部

Codeforces Round #716 (Div. 2) D. Cut and Stick (贪心,主席树)

  • 题意:给你一个序列,有\(q\)个询问,每次询问一个区间\([l,r]\),你要将这个区间内的数最少分成几个子序列,使得每个序列中的众数出现的次数不大于\(\lceil \frac{x}{2}\rceil\)(\(x\)为子序列区间长度).

  • 题解:假如区间内众数出现的次数\(cnt<=\lceil \frac{x}{2}\rceil\).我们就不需要分裂.否则,区间内不是众数的个数为\(x-cnt\),不难发现能构造出的最长区间一定是\(x-cnt+(x-cnt)+1\),即用这些不是众数的数去和众数放在一个子序列内, 这个序列构造完后,就只剩下众数了,他们只能单独一个数一个序列,那么答案就是\(x-(x-cnt+(x-cnt)+1)+1=2*cnt-x\).然后我们可以用主席树来求出区间内众数出现的次数,直接算答案即可.

  • 代码:

    #include <bits/stdc++.h>
    #define ll long long
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
     
    int n,q;
    int a[N];
    int root[N],idx;
     
    struct misaak{
    	int l,r;
    	int cnt;
    }tr[4*N+N*20];
     
     
    int build(int l,int r){
    	int p=++idx;
    	if(l==r) return p;
    	int mid=(l+r)>>1;
    	build(l,mid),build(mid+1,r);
    	return p;
    }
     
    int update(int p,int l,int r,int x){
    	int q=++idx;
    	tr[q]=tr[p];
    	tr[q].cnt++;
    	if(l==r) return q;
     
    	int mid=(l+r)>>1;
    	if(x<=mid) tr[q].l=update(tr[p].l,l,mid,x);
    	else tr[q].r=update(tr[p].r,mid+1,r,x);
    	
    	return q;
    }
     
    int query(int L,int R,int l,int r,int k){
    	if(l==r){
    		//cout<<L<<' '<<R<<' '<<tr[L].cnt<<' '<<tr[R].cnt<<'\n';
    		return tr[R].cnt-tr[L].cnt;
    	}
    	int cnt1=tr[tr[R].l].cnt-tr[tr[L].l].cnt;
    	int cnt2=tr[tr[R].r].cnt-tr[tr[L].r].cnt;
    	int mid=(l+r)>>1;
    	int res=0;
    	if(k<=cnt1) res=max(res,query(tr[L].l,tr[R].l,l,mid,k));
    	else if(k<=cnt2) res=max(res,query(tr[L].r,tr[R].r,mid+1,r,k));
    	return res;
    }
     
    int main() {
        ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    	cin>>n>>q;
    	rep(i,1,n) cin>>a[i];
     
    	root[0]=build(1,n);
     
    	rep(i,1,n){
    		root[i]=update(root[i-1],1,n,a[i]);
    	}
     
    	while(q--){
    		int l,r;
    		cin>>l>>r;
    		int res=query(root[l-1],root[r],1,n,(r-l+1)/2+1);
    		cout<<max(1,2*res-(r-l+1))<<'\n';
    	}
     
        return 0;
    }
    
posted @ 2021-04-26 17:45  _Kolibri  阅读(52)  评论(0)    收藏  举报