1 条题解

  • 0
    @ 2025-8-24 21:52:34

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar foreverlasting
    果然,失去别人远比自己离去更加令人恐惧。

    搬运于2025-08-24 21:52:34,当前版本为作者最后更新于2019-09-06 11:00:01,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    可以看这里哦

    一道杨表的神题。

    前置知识:杨表。

    杨表(又称为杨氏矩阵、杨图、Young DiagramYoung\ Diagram),是一种特殊的图,用于整数划分类问题上。

    杨表定义如下:

    对于一个nn的划分λ=(λ1,λ2,...)n\lambda=(\lambda_1,\lambda_2,...)\mapsto n定义为杨表为一个左对齐的方块组,其中第ii行有λi\lambda_i个方块。

    类似于这样

    (画的丑)

    我们定义钩子长h(u)h(u)Young DiagramYoung\ Diagram)为一个方块它下面的块数和它右边的块数之和(包括本身)。

    这里每个格子上的数字表示这个格子的钩子长

    我们定义标准杨表(SYTSYT)为将1,2,...,n{1,2,...,n}填入杨表且满足从上到下,从左到右数字都是满足比较方式<<的杨表。

    像这样

    我们再定义fλf^{\lambda}λ\lambda对应的标准杨表的个数。

    于是可以定义钩子公式:对于λn\lambda\mapsto n,有fλ=n!uλh(u)f^{\lambda}=\frac{n!}{\prod_{u\in \lambda}h(u)}

    证明考虑组合意义即可。

    下面再定义近似杨表(NYTNYT)为将nn个不同的数填入杨表且满足从上到下,从左到右数字都是满足比较方式<<的杨表。

    下面讲述如何构造近似杨表,我们考虑增量法。

    每次将一个新的元素插入时,先在第一行查找是否有其后继,若有,替换其后继,让其后继在下一行进行新的查找,递归下去。若无,则插入到这一行的末尾。这样每次插入元素的复杂度可以证明为O(rlogc)O(rlogc)rr为行数,cc为列数。

    同时根据RSKRSK算法,我们可以构造一个关于杨表二元组集合与nn个元素之间的双射,即S(P,Q)SnS_{(P,Q)}\leftrightarrow S_n,其中PP为近似杨表,QQ为标准杨表。RSKRSK算法不再过多赘述,感兴趣可以去wikiwiki一下,这道题只利用到这个算法中的一个性质,即对于任意排列πSn\pi\in S_n,其最长上升子序列的长度等于π\pi对于的PP的第一行长度。

    对于杨表,还有一个性质,即若将其的比较方式取反(<<\geq,>>\leq),所得杨表为原杨表的转置。(这里的转置定义为形状对称,并非元素对称,即元素可以滑动)


    接下来回到这道题。

    根据DilworthDilworth定理,我们可以知道一个序列的最长上升子序列的长度等于将其分为若干个不上升子序列所需数量的最小值。

    因此,题意转换成对于BB的每一个前缀,取出不超过kk个最长上升子序列,求最多能取走多少元素。

    再根据杨表的性质,我们可以知道求的这个东西即为该序列的不上升杨表中前kk行元素数量之和。

    于是我们将询问离线,等于每次插入一些元素,然后动态地维护前kk行的值即可。若暴力做,则是O(nrlogc)O(nrlogc)的,这样显然过不了。我们考虑总元素个数是O(n)O(n)的,于是对于每一个元素而言,它所在的行与列总有一个是n\leq \sqrt{n}的。对于行,我们直接维护前n\sqrt{n}行即可。对于列,我们将杨表的比较方式取反,维护转置后的前n\sqrt{n}行即可。于是复杂度就在O(nnlogn+qlogn)O(n\sqrt{n}logn+qlogn)或者O(nnlogn+qn)O(n\sqrt{n}logn+q\sqrt{n})了。

    code:

    //2019.9.6 by ljz
    //email 573902690@qq.com
    //if you find any bug in my code
    //please tell me
    #include<bits/stdc++.h>
    //#include<ext/pb_ds/tree_policy.hpp>
    //#include<ext/pb_ds/assoc_container.hpp>
    using namespace std;
    //using namespace __gnu_pbds;
    //using namespace __gnu_cxx;
    #define res register int
    #define LL long long
    #define inf 0x3f3f3f3f
    #define INF 0x3f3f3f3f3f3f3f
    #define unl __int128
    #define eps 5.6e-8
    #define RG register
    #define db double
    #define pc(x) __builtin_popcount(x)
    //#define pc(x) __builtin_popcountll(x)
    typedef pair<int,int> Pair;
    #define mp make_pair
    #define fi first
    #define se second
    #define pi acos(-1.0)
    #define pb push_back
    #define ull unsigned LL
    #define lowbit(x) (x&-x)
    #define gc getchar
    //template <class T>using Tree=tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;
    //inline char gc() {
    //    static char buf[100000],*p1,*p2;
    //    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    //}
    inline int read() {
        res s=0,ch=gc();
        while(ch<'0'||ch>'9')ch=gc();
        while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=gc();
        return s;
    }
    //inline int read() {
    //    res s=0,ch=gc(),w=1;
    //    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=gc();}
    //    while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=gc();
    //    return s*w;
    //}
    //inline LL Read() {
    //    RG LL s=0;
    //    res ch=gc();
    //    while(ch<'0'||ch>'9')ch=gc();
    //    while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=gc();
    //    return s;
    //}
    //inline LL Read() {
    //    RG LL s=0;
    //    res ch=gc(),w=1;
    //    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=gc();}
    //    while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=gc();
    //    return s*w;
    //}
    //inline void write(RG unl x){
    //    if(x>10)write(x/10);
    //    putchar(int(x%10)+'0');
    //}
    inline void swap(res &x,res &y) {
        x^=y^=x^=y;
    }
    //mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
    //clock_t start=clock();
    //inline void ck(){
    //    if(1.0*(clock()-start)/CLOCKS_PER_SEC>0.1)exit(0);
    //}
    const int kcz=998244353;
    const int N=2e5+10;
    const int M=300;
    namespace MAIN{
        inline void add(res &x,const res &y){
            x+=y,x>=kcz?x-=kcz:1;
        }
        inline int mul(const res &x,const res &y){
            return int(1LL*x*y%kcz);
        }
        inline int Add(const res &x,const res &y){
            return x+y>=kcz?x+y-kcz:x+y;
        }
        inline int qpow(res x,res y){
            res ret=1;
            while(y){
                if(y&1)ret=mul(ret,x);
                x=mul(x,x),y>>=1;
            }
            return ret;
        }
        int n,q;
        int tr[N];
        inline void modify(const res &x,const res &y){
            for(res i=x;i<=n;i+=lowbit(i))tr[i]+=y;
        }
        inline int query(const res &x){
            res ret=0;
            for(res i=x;i;i-=lowbit(i))ret+=tr[i];
            return ret;
        }
        int a[N];
        struct Que{
            int m,k,id;
            Que() {}
            Que(res m,res k,res id):m(m),k(k),id(id) {}
            inline bool operator < (const RG Que &b) const {
                return m<b.m;
            }
        }Q[N];
        int ans[N],bl;
        vector<int> YT[M],TY[M];
        inline void add(const res &va){
            for(res i=1,x=va;i<bl;i++){
                if(YT[i].empty()||YT[i].back()>=x){YT[i].pb(x),modify(i,1);break;}
                swap(YT[i][upper_bound(YT[i].begin(),YT[i].end(),x,greater<int>())-YT[i].begin()],x);
            }
            for(res i=1,x=va;i<bl;i++){
                if(TY[i].empty()||TY[i].back()<x){
                    TY[i].pb(x);
                    if(TY[i].size()>=bl)modify(int(TY[i].size()),1);
                    break;
                }
                swap(TY[i][lower_bound(TY[i].begin(),TY[i].end(),x)-TY[i].begin()],x);
            }
        }
        inline void MAIN(){
            n=read(),q=read(),bl=int(sqrt(n))+1;
            for(res i=1;i<=n;i++)a[i]=read();
            for(res i=1;i<=q;i++){
                res m=read(),k=read();
                Q[i]=Que(m,k,i);
            }
            sort(Q+1,Q+q+1);
            for(res i=1;i<=q;){
                res j=i;
                for(res k=Q[i-1].m+1;k<=Q[i].m;k++)add(a[k]);
                while(Q[j].m==Q[i].m&&j<=q)j++;
                j--;
                for(res k=i;k<=j;k++)ans[Q[k].id]=query(Q[k].k);
                i=j+1;
            }
            for(res i=1;i<=q;i++)printf("%d\n",ans[i]);
        }
    }
    int main(){
    //    srand(19260817);
    //    freopen("signin.in","r",stdin);
    //    freopen("signin.out","w",stdout);
        MAIN::MAIN();
        return 0;
    }
    
    • 1

    信息

    ID
    1417
    时间
    1000ms
    内存
    500MiB
    难度
    7
    标签
    递交数
    0
    已通过
    0
    上传者