• BZOJ5322:[JXOI2018]排序问题——题解


    https://www.lydsy.com/JudgeOnline/problem.php?id=5322

    https://loj.ac/problem/2543 <-可以看数据,要没有这数据我死活调不出来。

    https://www.luogu.org/problemnew/show/P4561

    题面见上。

    我们知道可重元素全排列=元素个数!/(每个元素个数!加和)。

    所以一个很显然的贪心就是我们取元素使得每个元素的个数都尽可能小。

    我们先离散化,然后二分出sum,表示l~r我每个元素都取至少sum个(“至少”表示原数列可能有l~r的元素且其个数可能超过了sum个)。

    然后各种处理我们就能得到(每个元素个数!加和)了,怎么样,是不是很好想呢?

    然而不好写

    注意二分上界为n+m原因就是l~r的元素可能出现在原序列且其个数为n。

    #include<cmath>
    #include<queue>
    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=2e5+5;
    const int M=1e7+N;
    const int p=998244353;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    ll qpow(ll k,int n){
        ll res=1;
        while(n){
        if(n&1)res=res*k%p;
        k=k*k%p;n>>=1;
        }
        return res;
    }
    int jc[M];
    int a[N],b[N],num[N];
    int n,m,l,r,t,cnt;
    inline ll calc(int k){
        ll sum=(ll)k*cnt;
        for(int i=l;i<=r;i++){
        if(num[i]<k)sum+=k-num[i];
        }
        return sum;
    }
    void work(){
        for(int i=1;i<=n;i++)num[a[i]]++;
        int L=0,R=n+m;
        while(L<R){
        int mid=(L+R+1)>>1;
        if(calc(mid)<=m)L=mid;
        else R=mid-1;
        }
        ll ans=1;
        int last=m-calc(L);
        for(int i=1;i<=t;i++){
        if(i<l||r<i)ans=ans*jc[num[i]]%p;
        else{
            if(num[i]>L)ans=ans*jc[num[i]]%p;
            else if(last)last--,ans=ans*jc[L+1]%p;
            else ans=ans*jc[L]%p;
        }
        }
        ans=ans*qpow(jc[L+1],last)%p*qpow(jc[L],cnt-last)%p;
        printf("%lld
    ",qpow(ans,p-2)*jc[n+m]%p);
    }
    void LSH(){
        sort(b+1,b+n+1);
        t=unique(b+1,b+n+1)-b-1;
        for(int i=1;i<=t;i++)num[i]=0;
        for(int i=1;i<=n;i++){
        a[i]=lower_bound(b+1,b+t+1,a[i])-b;
        }
        cnt=r-l;
        l=lower_bound(b+1,b+t+1,l)-b;
        r=upper_bound(b+1,b+t+1,r)-b-1;
        cnt-=r-l;
    }
    int main(){
        jc[0]=1;
        for(int i=1;i<M;i++)jc[i]=(ll)jc[i-1]*i%p;
        int T=read();
        while(T--){
        n=read(),m=read(),l=read(),r=read();
        for(int i=1;i<=n;i++)a[i]=b[i]=read();
        LSH();
        work();
        }
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

    +本文作者:luyouqi233。               +

    +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    偏最小二乘法回归(Partial Least Squares Regression)
    今天就来聊聊产品运营
    VS2005终于不“变态”了!
    Android 里的对话框Dialog 实现机制基础
    C#多线程操作界面控件的解决方案
    转C++ ,C#数据类型对照
    关于Linq to sql 应用时出现的一个‘row not found or changed’ 异常
    Android之Context Memu
    HttpModule的认识
    Docker:官网文档 Get Started 笔记
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9081372.html
Copyright © 2020-2023  润新知